mirror of
https://github.com/nvim-tree/nvim-tree.lua.git
synced 2026-07-28 07:49:46 +05:30
Compare commits
5 Commits
0815349cc0
...
feat/renam
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27aeba9b03 | ||
|
|
cf18a662cd | ||
|
|
0d1176b4c5 | ||
|
|
85a743b8f1 | ||
|
|
68992ee244 |
@@ -1911,6 +1911,11 @@ Config: experimental *nvim-tree-config-experimental*
|
||||
In the event of a problem please disable the experiment and raise an
|
||||
issue.
|
||||
|
||||
Fields: ~
|
||||
• {session_restore_nvim}? (`boolean`, default: `false`) Restore
|
||||
nvim-tree buffers when restoring vim sessions
|
||||
(requires 0.13+).
|
||||
|
||||
==============================================================================
|
||||
Config: log *nvim-tree-config-log*
|
||||
|
||||
@@ -2216,6 +2221,7 @@ Following is the default configuration, see |nvim_tree.config| for details. >lua
|
||||
persist = false,
|
||||
},
|
||||
experimental = {
|
||||
session_restore_nvim = false
|
||||
},
|
||||
log = {
|
||||
enable = false,
|
||||
|
||||
@@ -9,6 +9,9 @@ error("Cannot require a meta file")
|
||||
---
|
||||
---@class nvim_tree.config.experimental
|
||||
---
|
||||
---Restore nvim-tree buffers when restoring vim sessions (requires 0.13+).
|
||||
---(default: `false`)
|
||||
---@field session_restore_nvim? boolean
|
||||
--Example below for future reference:
|
||||
--
|
||||
--Buffers opened by nvim-tree will use with relative paths instead of absolute.
|
||||
|
||||
@@ -3,6 +3,7 @@ local utils = require("nvim-tree.utils")
|
||||
local events = require("nvim-tree.events")
|
||||
local notify = require("nvim-tree.notify")
|
||||
local config = require("nvim-tree.config")
|
||||
local lib = require("nvim-tree.lib")
|
||||
|
||||
local find_file = require("nvim-tree.actions.finders.find-file").fn
|
||||
|
||||
@@ -47,7 +48,9 @@ end
|
||||
|
||||
---@param node Node
|
||||
---@param to string
|
||||
function M.rename(node, to)
|
||||
---@param opts? { notify?: boolean }
|
||||
function M.rename(node, to, opts)
|
||||
opts = opts and opts or {}
|
||||
local notify_from = notify.render_path(node.absolute_path)
|
||||
local notify_to = notify.render_path(to)
|
||||
|
||||
@@ -92,7 +95,9 @@ function M.rename(node, to)
|
||||
end
|
||||
|
||||
if not is_error then
|
||||
notify.info(string.format("%s -> %s", notify_from, notify_to))
|
||||
if opts.notify ~= false then
|
||||
notify.info(string.format("%s -> %s", notify_from, notify_to))
|
||||
end
|
||||
utils.rename_loaded_buffers(node.absolute_path, to)
|
||||
events._dispatch_node_renamed(node.absolute_path, to)
|
||||
end
|
||||
@@ -192,4 +197,24 @@ function M.rename_full(node)
|
||||
prompt_to_rename(node, ":p")
|
||||
end
|
||||
|
||||
---@param nodes Node[]
|
||||
---@param old_part string
|
||||
---@param new_part string
|
||||
function M.bulk_rename(nodes, old_part, new_part)
|
||||
local prompt_select = string.format("Substitute '%s' for '%s' in %s files?", old_part, new_part, #nodes)
|
||||
|
||||
lib.prompt(prompt_select .. " Y/n: ", prompt_select, ({ "", "y" }), { "No", "Yes" }, "nvimtree_bulk_rename", function(answer)
|
||||
utils.clear_prompt()
|
||||
if answer == "n" then return end
|
||||
|
||||
for _, node in ipairs(nodes) do
|
||||
local new_name = node.name:gsub(old_part, new_part)
|
||||
local new_full_path = vim.fn.fnamemodify(node.absolute_path, ":h") .. "/" .. new_name
|
||||
M.rename(node, new_full_path, { notify = false })
|
||||
end
|
||||
|
||||
notify.info(string.format("%s nodes substituted from %s -> %s", #nodes, old_part, new_part))
|
||||
end)
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -17,6 +17,28 @@ function M.global()
|
||||
end,
|
||||
})
|
||||
|
||||
if vim.fn.has("nvim-0.13") == 1 and config.g.experimental.session_restore_nvim then
|
||||
vim.api.nvim_create_autocmd("SessionWritePre", { ---@diagnostic disable-line: param-type-mismatch
|
||||
group = augroup_id,
|
||||
callback = function()
|
||||
-- We must schedule to wait until `vim.v.this_session` is properly updated
|
||||
-- This prevents overwriting the data if a new session is created with a new `:mksession`
|
||||
vim.schedule(require("nvim-tree.session").save)
|
||||
end,
|
||||
})
|
||||
|
||||
vim.api.nvim_create_autocmd("SessionLoadPost", {
|
||||
group = augroup_id,
|
||||
-- Workaround: this event fires multiple times (report upstream),
|
||||
-- failure notifications could show up many times.
|
||||
once = true,
|
||||
callback = function()
|
||||
require("nvim-tree.session").restore()
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
if config.g.tab.sync.open then
|
||||
vim.api.nvim_create_autocmd("TabEnter", {
|
||||
group = augroup_id,
|
||||
@@ -140,6 +162,52 @@ function M.global()
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
vim.api.nvim_create_autocmd("CmdlineLeave", {
|
||||
group = augroup_id,
|
||||
pattern = ":",
|
||||
callback = function(ev)
|
||||
if require("nvim-tree.view").get_bufnr() == ev.buf then
|
||||
local cmd = vim.fn.getcmdline()
|
||||
|
||||
if cmd:match("s([^%w])") then
|
||||
local delimiter = cmd:match("s([^%w])")
|
||||
local escaped_delim = delimiter:gsub("[%%%.%+%-%*%?%^%$%(%)%[%]]", "%%%1")
|
||||
|
||||
-- Looks for: s <delimiter> <old> <delimiter> <new> <delimiter or end>
|
||||
local pattern = "s" .. escaped_delim .. "([^" .. escaped_delim .. "]*)" .. escaped_delim .. "([^" .. escaped_delim .. "]*)"
|
||||
|
||||
local old_part, new_part = cmd:match(pattern)
|
||||
|
||||
local core = require("nvim-tree.core")
|
||||
local explorer = core.get_explorer()
|
||||
local utils = require("nvim-tree.utils")
|
||||
local bulk_rename = require("nvim-tree.actions.fs.rename-file").bulk_rename
|
||||
|
||||
local visual_marker = "'<,'>"
|
||||
local nodes = cmd:sub(1, #visual_marker) == visual_marker and
|
||||
utils.get_visual_nodes({ use_native = true, should_exit = false }) or
|
||||
explorer and explorer:get_nodes_by_line(core.get_nodes_starting_line()) or {}
|
||||
local matching_nodes = {}
|
||||
|
||||
for i = #nodes, 1, -1 do
|
||||
local node = nodes[i]
|
||||
if node and node.name:find(old_part) ~= nil then
|
||||
table.insert(matching_nodes, node)
|
||||
end
|
||||
end
|
||||
|
||||
if #matching_nodes > 0 then
|
||||
bulk_rename(matching_nodes, old_part, new_part)
|
||||
else
|
||||
require("nvim-tree.notify").notify(string.format("Not matching nodes with '%s'", old_part))
|
||||
end
|
||||
|
||||
vim.fn.setcmdline("")
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -297,6 +297,7 @@ M.d = { -- config-default-start
|
||||
persist = false,
|
||||
},
|
||||
experimental = {
|
||||
session_restore_nvim = false
|
||||
},
|
||||
log = {
|
||||
enable = false,
|
||||
|
||||
103
lua/nvim-tree/session.lua
Normal file
103
lua/nvim-tree/session.lua
Normal file
@@ -0,0 +1,103 @@
|
||||
local notify = require("nvim-tree.notify")
|
||||
|
||||
local M = {}
|
||||
|
||||
local storepath = vim.fn.stdpath("data") .. "/nvim-tree-session.json"
|
||||
|
||||
local function decode_session_file()
|
||||
local file = io.open(storepath, "r")
|
||||
|
||||
if file then
|
||||
local content = file:read("*all")
|
||||
file:close()
|
||||
if content and content ~= "" then
|
||||
return vim.json.decode(content)
|
||||
end
|
||||
end
|
||||
-- Notifying on failure could be noisy, as it'd happen if the file simply did not exist
|
||||
end
|
||||
|
||||
local function write_session_file(session_file_content)
|
||||
local file, errmsg = io.open(storepath, "w")
|
||||
|
||||
if file then
|
||||
file:write(vim.json.encode(session_file_content))
|
||||
file:close()
|
||||
else
|
||||
notify.warn(string.format("Invalid session file (%s): %s", storepath, errmsg))
|
||||
end
|
||||
end
|
||||
|
||||
function M.save()
|
||||
-- We either always save the session data, which ends up populating the storepath with empty data
|
||||
-- Or we gate by the tree's visibility, which could create "out of sync" scenario:
|
||||
-- if the tree is initially open and the session is saved, it won't be overridden later,
|
||||
-- if the tree is no longer visible. However, when restoring, this is harmless.
|
||||
if require("nvim-tree.api").tree.is_visible({ any_tabpage = true }) then
|
||||
local ok, session_file_content = pcall(decode_session_file)
|
||||
|
||||
if not ok then
|
||||
notify.warn(string.format("Failed to decode session file (%s): %s", storepath, session_file_content))
|
||||
return
|
||||
end
|
||||
|
||||
-- might be nil at this point
|
||||
session_file_content = session_file_content or {}
|
||||
|
||||
local cwd = require("nvim-tree.core").get_cwd()
|
||||
|
||||
session_file_content[vim.v.this_session] = { cwd = cwd }
|
||||
|
||||
local ok2, err = pcall(write_session_file, session_file_content)
|
||||
|
||||
if not ok2 then
|
||||
notify.warn(string.format("Failed to write session file (%s): %s", storepath, err))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.restore()
|
||||
local api = require("nvim-tree.api").tree
|
||||
|
||||
---@type table<integer,boolean>
|
||||
local tabs = {}
|
||||
|
||||
local ok, session_file_content = pcall(decode_session_file)
|
||||
|
||||
-- Failing to restore cwd is not fatal, we can continue
|
||||
if not ok then
|
||||
notify.warn(string.format("Failed to decode session file (%s): %s", storepath, session_file_content))
|
||||
end
|
||||
|
||||
local path = session_file_content and session_file_content[vim.v.this_session] and session_file_content[vim.v.this_session].cwd or nil
|
||||
|
||||
-- Save tabs with leftover nvim-tree buffers
|
||||
for _, tab in ipairs(vim.api.nvim_list_tabpages()) do
|
||||
for _, win in ipairs(vim.api.nvim_tabpage_list_wins(tab)) do
|
||||
local buf = vim.api.nvim_win_get_buf(win)
|
||||
if api.is_tree_buf(buf) then
|
||||
tabs[tab] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- The new window may inherit options from the current one if we don't schedule
|
||||
vim.schedule(function()
|
||||
api.close_in_all_tabs()
|
||||
|
||||
for tab, _ in pairs(tabs) do
|
||||
if vim.api.nvim_tabpage_is_valid(tab) then
|
||||
local win = vim.api.nvim_tabpage_get_win(tab)
|
||||
|
||||
-- Invoke `open` from each tab's current window to prevent having to switch tabs
|
||||
if vim.api.nvim_win_is_valid(win) then
|
||||
vim.api.nvim_win_call(win, function()
|
||||
api.open({ path = path })
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -527,19 +527,25 @@ function M.exit_visual_mode()
|
||||
end
|
||||
|
||||
---Get the visual selection range nodes, exiting visual mode.
|
||||
---@param opts? { should_exit?: boolean, use_native?: boolean }
|
||||
---@return Node[]?
|
||||
function M.get_visual_nodes()
|
||||
function M.get_visual_nodes(opts)
|
||||
opts = opts and opts or {}
|
||||
|
||||
local explorer = require("nvim-tree.core").get_explorer()
|
||||
if not explorer then
|
||||
return nil
|
||||
end
|
||||
local start_line = vim.fn.line("v")
|
||||
local end_line = vim.fn.line(".")
|
||||
local start_line = vim.fn.line(opts.use_native == true and "'<" or "v")
|
||||
local end_line = vim.fn.line(opts.use_native == true and "'>" or ".")
|
||||
if start_line > end_line then
|
||||
start_line, end_line = end_line, start_line
|
||||
end
|
||||
local nodes = explorer:get_nodes_in_range(start_line, end_line)
|
||||
M.exit_visual_mode()
|
||||
|
||||
if opts.should_exit ~= false then
|
||||
M.exit_visual_mode()
|
||||
end
|
||||
return nodes
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user