mirror of
https://github.com/nvim-tree/nvim-tree.lua.git
synced 2026-07-28 07:49:46 +05:30
Compare commits
7 Commits
0d1176b4c5
...
27aeba9b03
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27aeba9b03 | ||
|
|
cf18a662cd | ||
|
|
a797d5e201 | ||
|
|
35d3511e7a | ||
|
|
7ff7040bf6 | ||
|
|
531b807b8f | ||
|
|
c760c92667 |
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
".": "1.17.0"
|
".": "1.18.0"
|
||||||
}
|
}
|
||||||
|
|||||||
15
CHANGELOG.md
15
CHANGELOG.md
@@ -1,5 +1,20 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [1.18.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.17.0...nvim-tree-v1.18.0) (2026-07-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **#1549:** p will paste files from another nvim-tree instance, gp will cut/paste ([#3336](https://github.com/nvim-tree/nvim-tree.lua/issues/3336)) ([c760c92](https://github.com/nvim-tree/nvim-tree.lua/commit/c760c92667fe5febf99e2a5bb8a543b0208c743b))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **#3312:** correct cursor when full name shown, requires nvim 0.12.2+ ([#3316](https://github.com/nvim-tree/nvim-tree.lua/issues/3316)) ([d277467](https://github.com/nvim-tree/nvim-tree.lua/commit/d277467fc0d1d0e2bca88165a1de6b526f9f6fe8))
|
||||||
|
* **#3324:** deprecated BufModifiedSet event replaced by OptionSet event for Nvim 0.13+ ([#3325](https://github.com/nvim-tree/nvim-tree.lua/issues/3325)) ([f9bfc00](https://github.com/nvim-tree/nvim-tree.lua/commit/f9bfc0059eca24546b69a7006110463da4808f8f))
|
||||||
|
* **#3327:** pass nvim_tree.api.node.open.Opts to all applicable nvim_tree.api.node.open function ([#3329](https://github.com/nvim-tree/nvim-tree.lua/issues/3329)) ([07f541f](https://github.com/nvim-tree/nvim-tree.lua/commit/07f541fcaa4a5ae019598240362449ab7e9812b3))
|
||||||
|
* **full-name:** lower `zindex` to get consistent cursor shape ([d277467](https://github.com/nvim-tree/nvim-tree.lua/commit/d277467fc0d1d0e2bca88165a1de6b526f9f6fe8))
|
||||||
|
|
||||||
## [1.17.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.16.0...nvim-tree-v1.17.0) (2026-04-07)
|
## [1.17.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.16.0...nvim-tree-v1.17.0) (2026-04-07)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,9 @@
|
|||||||
|
|
||||||
(Live) filtering
|
(Live) filtering
|
||||||
|
|
||||||
Cut, copy, paste, rename, delete, create
|
Rename, delete, create
|
||||||
|
|
||||||
|
Cut, copy, paste locally and between instances
|
||||||
|
|
||||||
Highly customisable
|
Highly customisable
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ Features
|
|||||||
- Git integration
|
- Git integration
|
||||||
- Diagnostics integration: LSP and COC
|
- Diagnostics integration: LSP and COC
|
||||||
- (Live) filtering
|
- (Live) filtering
|
||||||
- Cut, copy, paste, rename, delete, create
|
- Rename, delete, create
|
||||||
|
- Cut, copy, paste locally and between instances
|
||||||
- Highly customisable
|
- Highly customisable
|
||||||
|
|
||||||
File Icons
|
File Icons
|
||||||
@@ -142,7 +143,7 @@ Show the mappings: `g?`
|
|||||||
`F` n Live Filter: Clear |nvim_tree.api.filter.live.clear()|
|
`F` n Live Filter: Clear |nvim_tree.api.filter.live.clear()|
|
||||||
`f` n Live Filter: Start |nvim_tree.api.filter.live.start()|
|
`f` n Live Filter: Start |nvim_tree.api.filter.live.start()|
|
||||||
`g?` n Help |nvim_tree.api.tree.toggle_help()|
|
`g?` n Help |nvim_tree.api.tree.toggle_help()|
|
||||||
`gy` n Copy Absolute Path |nvim_tree.api.fs.copy.absolute_path()|
|
`gy` nx Copy Absolute Path |nvim_tree.api.fs.copy.absolute_path()|
|
||||||
`ge` n Copy Basename |nvim_tree.api.fs.copy.basename()|
|
`ge` n Copy Basename |nvim_tree.api.fs.copy.basename()|
|
||||||
`H` n Toggle Filter: Dotfiles |nvim_tree.api.filter.dotfiles.toggle()|
|
`H` n Toggle Filter: Dotfiles |nvim_tree.api.filter.dotfiles.toggle()|
|
||||||
`I` n Toggle Filter: Git Ignored |nvim_tree.api.filter.git.ignored.toggle()|
|
`I` n Toggle Filter: Git Ignored |nvim_tree.api.filter.git.ignored.toggle()|
|
||||||
@@ -154,6 +155,7 @@ Show the mappings: `g?`
|
|||||||
`o` n Open |nvim_tree.api.node.open.edit()|
|
`o` n Open |nvim_tree.api.node.open.edit()|
|
||||||
`O` n Open: No Window Picker |nvim_tree.api.node.open.no_window_picker()|
|
`O` n Open: No Window Picker |nvim_tree.api.node.open.no_window_picker()|
|
||||||
`p` n Paste |nvim_tree.api.fs.paste()|
|
`p` n Paste |nvim_tree.api.fs.paste()|
|
||||||
|
`gp` n Move |nvim_tree.api.fs.move()|
|
||||||
`P` n Parent Directory |nvim_tree.api.node.navigate.parent()|
|
`P` n Parent Directory |nvim_tree.api.node.navigate.parent()|
|
||||||
`q` n Close |nvim_tree.api.tree.close()|
|
`q` n Close |nvim_tree.api.tree.close()|
|
||||||
`r` n Rename |nvim_tree.api.fs.rename()|
|
`r` n Rename |nvim_tree.api.fs.rename()|
|
||||||
@@ -435,7 +437,7 @@ You are encouraged to copy these to your {on_attach} function. >lua
|
|||||||
vim.keymap.set("n", "F", api.filter.live.clear, opts("Live Filter: Clear"))
|
vim.keymap.set("n", "F", api.filter.live.clear, opts("Live Filter: Clear"))
|
||||||
vim.keymap.set("n", "f", api.filter.live.start, opts("Live Filter: Start"))
|
vim.keymap.set("n", "f", api.filter.live.start, opts("Live Filter: Start"))
|
||||||
vim.keymap.set("n", "g?", api.tree.toggle_help, opts("Help"))
|
vim.keymap.set("n", "g?", api.tree.toggle_help, opts("Help"))
|
||||||
vim.keymap.set("n", "gy", api.fs.copy.absolute_path, opts("Copy Absolute Path"))
|
vim.keymap.set({ "n", "x" }, "gy", api.fs.copy.absolute_path, opts("Copy Absolute Path"))
|
||||||
vim.keymap.set("n", "ge", api.fs.copy.basename, opts("Copy Basename"))
|
vim.keymap.set("n", "ge", api.fs.copy.basename, opts("Copy Basename"))
|
||||||
vim.keymap.set("n", "H", api.filter.dotfiles.toggle, opts("Toggle Filter: Dotfiles"))
|
vim.keymap.set("n", "H", api.filter.dotfiles.toggle, opts("Toggle Filter: Dotfiles"))
|
||||||
vim.keymap.set("n", "I", api.filter.git.ignored.toggle, opts("Toggle Filter: Git Ignored"))
|
vim.keymap.set("n", "I", api.filter.git.ignored.toggle, opts("Toggle Filter: Git Ignored"))
|
||||||
@@ -447,6 +449,7 @@ You are encouraged to copy these to your {on_attach} function. >lua
|
|||||||
vim.keymap.set("n", "o", api.node.open.edit, opts("Open"))
|
vim.keymap.set("n", "o", api.node.open.edit, opts("Open"))
|
||||||
vim.keymap.set("n", "O", api.node.open.no_window_picker, opts("Open: No Window Picker"))
|
vim.keymap.set("n", "O", api.node.open.no_window_picker, opts("Open: No Window Picker"))
|
||||||
vim.keymap.set("n", "p", api.fs.paste, opts("Paste"))
|
vim.keymap.set("n", "p", api.fs.paste, opts("Paste"))
|
||||||
|
vim.keymap.set("n", "gp", api.fs.move, opts("Move"))
|
||||||
vim.keymap.set("n", "P", api.node.navigate.parent, opts("Parent Directory"))
|
vim.keymap.set("n", "P", api.node.navigate.parent, opts("Parent Directory"))
|
||||||
vim.keymap.set("n", "q", api.tree.close, opts("Close"))
|
vim.keymap.set("n", "q", api.tree.close, opts("Close"))
|
||||||
vim.keymap.set("n", "r", api.fs.rename, opts("Rename"))
|
vim.keymap.set("n", "r", api.fs.rename, opts("Rename"))
|
||||||
@@ -1908,6 +1911,11 @@ Config: experimental *nvim-tree-config-experimental*
|
|||||||
In the event of a problem please disable the experiment and raise an
|
In the event of a problem please disable the experiment and raise an
|
||||||
issue.
|
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*
|
Config: log *nvim-tree-config-log*
|
||||||
|
|
||||||
@@ -2213,6 +2221,7 @@ Following is the default configuration, see |nvim_tree.config| for details. >lua
|
|||||||
persist = false,
|
persist = false,
|
||||||
},
|
},
|
||||||
experimental = {
|
experimental = {
|
||||||
|
session_restore_nvim = false
|
||||||
},
|
},
|
||||||
log = {
|
log = {
|
||||||
enable = false,
|
enable = false,
|
||||||
@@ -2459,8 +2468,20 @@ cut({node}) *nvim_tree.api.fs.cut()*
|
|||||||
Parameters: ~
|
Parameters: ~
|
||||||
• {node} (`nvim_tree.api.Node?`)
|
• {node} (`nvim_tree.api.Node?`)
|
||||||
|
|
||||||
|
move({node}) *nvim_tree.api.fs.move()*
|
||||||
|
Paste while cutting files from:
|
||||||
|
• current nvim-tree clipboard (if present)
|
||||||
|
• another nvim-tree instance via system clipboard
|
||||||
|
|
||||||
|
If {node} is a file it will pasted in the parent directory.
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
• {node} (`nvim_tree.api.Node?`)
|
||||||
|
|
||||||
paste({node}) *nvim_tree.api.fs.paste()*
|
paste({node}) *nvim_tree.api.fs.paste()*
|
||||||
Paste from the nvim-tree clipboard.
|
Paste files from:
|
||||||
|
• current nvim-tree clipboard (if present)
|
||||||
|
• another nvim-tree instance via system clipboard
|
||||||
|
|
||||||
If {node} is a file it will pasted in the parent directory.
|
If {node} is a file it will pasted in the parent directory.
|
||||||
|
|
||||||
|
|||||||
@@ -59,13 +59,25 @@ function nvim_tree.api.fs.create(node) end
|
|||||||
function nvim_tree.api.fs.cut(node) end
|
function nvim_tree.api.fs.cut(node) end
|
||||||
|
|
||||||
---
|
---
|
||||||
---Paste from the nvim-tree clipboard.
|
---Paste files from:
|
||||||
|
---- current nvim-tree clipboard (if present)
|
||||||
|
---- another nvim-tree instance via system clipboard
|
||||||
---
|
---
|
||||||
---If {node} is a file it will pasted in the parent directory.
|
---If {node} is a file it will pasted in the parent directory.
|
||||||
---
|
---
|
||||||
---@param node? nvim_tree.api.Node
|
---@param node? nvim_tree.api.Node
|
||||||
function nvim_tree.api.fs.paste(node) end
|
function nvim_tree.api.fs.paste(node) end
|
||||||
|
|
||||||
|
---
|
||||||
|
---Paste while cutting files from:
|
||||||
|
---- current nvim-tree clipboard (if present)
|
||||||
|
---- another nvim-tree instance via system clipboard
|
||||||
|
---
|
||||||
|
---If {node} is a file it will pasted in the parent directory.
|
||||||
|
---
|
||||||
|
---@param node? nvim_tree.api.Node
|
||||||
|
function nvim_tree.api.fs.move(node) end
|
||||||
|
|
||||||
---
|
---
|
||||||
---Print the contents of the nvim-tree clipboard.
|
---Print the contents of the nvim-tree clipboard.
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ error("Cannot require a meta file")
|
|||||||
---
|
---
|
||||||
---@class nvim_tree.config.experimental
|
---@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:
|
--Example below for future reference:
|
||||||
--
|
--
|
||||||
--Buffers opened by nvim-tree will use with relative paths instead of absolute.
|
--Buffers opened by nvim-tree will use with relative paths instead of absolute.
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ local find_file = require("nvim-tree.actions.finders.find-file").fn
|
|||||||
|
|
||||||
local Class = require("nvim-tree.classic")
|
local Class = require("nvim-tree.classic")
|
||||||
local DirectoryNode = require("nvim-tree.node.directory")
|
local DirectoryNode = require("nvim-tree.node.directory")
|
||||||
|
local FileNode = require("nvim-tree.node.file")
|
||||||
local Node = require("nvim-tree.node")
|
local Node = require("nvim-tree.node")
|
||||||
|
|
||||||
---@alias ClipboardAction "copy" | "cut"
|
---@alias ClipboardAction "copy" | "cut"
|
||||||
@@ -176,28 +177,40 @@ function Clipboard:bulk_clipboard(nodes, from, to, verb)
|
|||||||
self.explorer.renderer:draw()
|
self.explorer.renderer:draw()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@private
|
||||||
|
---@param node_or_nodes Node|Node[]
|
||||||
|
---@return boolean
|
||||||
|
function Clipboard:is_nodes_array(node_or_nodes)
|
||||||
|
if type(node_or_nodes) == "table" and node_or_nodes.is and node_or_nodes:is(Node) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
---Copy one or more nodes
|
---Copy one or more nodes
|
||||||
---@param node_or_nodes Node|Node[]
|
---@param node_or_nodes Node|Node[]
|
||||||
function Clipboard:copy(node_or_nodes)
|
function Clipboard:copy(node_or_nodes)
|
||||||
if type(node_or_nodes) == "table" and node_or_nodes.is and node_or_nodes:is(Node) then
|
if self:is_nodes_array(node_or_nodes) == false then
|
||||||
utils.array_remove(self.data.cut, node_or_nodes)
|
utils.array_remove(self.data.cut, node_or_nodes)
|
||||||
toggle(node_or_nodes, self.data.copy)
|
toggle(node_or_nodes, self.data.copy)
|
||||||
self.explorer.renderer:draw()
|
self.explorer.renderer:draw()
|
||||||
else
|
else
|
||||||
self:bulk_clipboard(utils.filter_descendant_nodes(node_or_nodes), self.data.cut, self.data.copy, "added to")
|
self:bulk_clipboard(utils.filter_descendant_nodes(node_or_nodes), self.data.cut, self.data.copy, "added to")
|
||||||
end
|
end
|
||||||
|
self:copy_absolute_path(self.data.copy, { notify = false })
|
||||||
end
|
end
|
||||||
|
|
||||||
---Cut one or more nodes
|
---Cut one or more nodes
|
||||||
---@param node_or_nodes Node|Node[]
|
---@param node_or_nodes Node|Node[]
|
||||||
function Clipboard:cut(node_or_nodes)
|
function Clipboard:cut(node_or_nodes)
|
||||||
if type(node_or_nodes) == "table" and node_or_nodes.is and node_or_nodes:is(Node) then
|
if self:is_nodes_array(node_or_nodes) == false then
|
||||||
utils.array_remove(self.data.copy, node_or_nodes)
|
utils.array_remove(self.data.copy, node_or_nodes)
|
||||||
toggle(node_or_nodes, self.data.cut)
|
toggle(node_or_nodes, self.data.cut)
|
||||||
self.explorer.renderer:draw()
|
self.explorer.renderer:draw()
|
||||||
else
|
else
|
||||||
self:bulk_clipboard(utils.filter_descendant_nodes(node_or_nodes), self.data.copy, self.data.cut, "cut to")
|
self:bulk_clipboard(utils.filter_descendant_nodes(node_or_nodes), self.data.copy, self.data.cut, "cut to")
|
||||||
end
|
end
|
||||||
|
self:copy_absolute_path(self.data.cut, { notify = false })
|
||||||
end
|
end
|
||||||
|
|
||||||
---Clear clipboard for action and reload to reflect filesystem changes from paste.
|
---Clear clipboard for action and reload to reflect filesystem changes from paste.
|
||||||
@@ -304,6 +317,40 @@ function Clipboard:resolve_conflicts(conflict, destination, action, action_fn)
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Transforms the copied absolute paths on register to node
|
||||||
|
---@private
|
||||||
|
function Clipboard:get_nodes_from_reg()
|
||||||
|
local content = vim.fn.getreg(self.reg)
|
||||||
|
|
||||||
|
if #content == 0 then
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local nodes = {}
|
||||||
|
local absolute_paths = vim.split(content:sub(1, #content), "\n")
|
||||||
|
|
||||||
|
for _, absolute_path in ipairs(absolute_paths) do
|
||||||
|
if absolute_path:match("^%s*(.-)%s*s") then
|
||||||
|
local node_args = { absolute_path = absolute_path, name = vim.fn.fnamemodify(absolute_path, ":t"), explorer = self.explorer }
|
||||||
|
if absolute_path:sub(-1) == "/" then
|
||||||
|
node_args.name = vim.fn.fnamemodify(absolute_path:sub(1, -2), ":t")
|
||||||
|
table.insert(nodes, DirectoryNode(node_args))
|
||||||
|
else
|
||||||
|
table.insert(nodes, FileNode(node_args))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nodes
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param nodes Node[]
|
||||||
|
---@private
|
||||||
|
function Clipboard:destroy_nodes(nodes)
|
||||||
|
for _, n in ipairs(nodes) do
|
||||||
|
n:destroy()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
---Paste cut or copy with batch conflict resolution.
|
---Paste cut or copy with batch conflict resolution.
|
||||||
---@private
|
---@private
|
||||||
---@param node Node
|
---@param node Node
|
||||||
@@ -318,7 +365,9 @@ function Clipboard:do_paste(node, action, action_fn)
|
|||||||
node = dir:last_group_node()
|
node = dir:last_group_node()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local clip = self.data[action]
|
local is_local = #self.data[action] > 0
|
||||||
|
local clip = is_local and self.data[action] or self:get_nodes_from_reg()
|
||||||
|
|
||||||
if #clip == 0 then
|
if #clip == 0 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -328,6 +377,9 @@ function Clipboard:do_paste(node, action, action_fn)
|
|||||||
if not stats and err_name ~= "ENOENT" then
|
if not stats and err_name ~= "ENOENT" then
|
||||||
log.line("copy_paste", "do_paste fs_stat '%s' failed '%s'", destination, err)
|
log.line("copy_paste", "do_paste fs_stat '%s' failed '%s'", destination, err)
|
||||||
notify.error("Could not " .. action .. " " .. notify.render_path(destination) .. " - " .. (err or "???"))
|
notify.error("Could not " .. action .. " " .. notify.render_path(destination) .. " - " .. (err or "???"))
|
||||||
|
if is_local == false then
|
||||||
|
self:destroy_nodes(clip)
|
||||||
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local is_dir = stats and stats.type == "directory"
|
local is_dir = stats and stats.type == "directory"
|
||||||
@@ -359,6 +411,10 @@ function Clipboard:do_paste(node, action, action_fn)
|
|||||||
else
|
else
|
||||||
self:finish_paste(action)
|
self:finish_paste(action)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if is_local == false then
|
||||||
|
self:destroy_nodes(clip)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param source string
|
---@param source string
|
||||||
@@ -386,10 +442,12 @@ end
|
|||||||
|
|
||||||
---Paste cut (if present) or copy (if present)
|
---Paste cut (if present) or copy (if present)
|
||||||
---@param node Node
|
---@param node Node
|
||||||
function Clipboard:paste(node)
|
---@param opts? { cut?: boolean }
|
||||||
if self.data.cut[1] ~= nil then
|
function Clipboard:paste(node, opts)
|
||||||
|
opts = opts and opts or {}
|
||||||
|
if self.data.cut[1] ~= nil or opts.cut == true then
|
||||||
self:do_paste(node, "cut", do_cut)
|
self:do_paste(node, "cut", do_cut)
|
||||||
elseif self.data.copy[1] ~= nil then
|
else
|
||||||
self:do_paste(node, "copy", do_copy)
|
self:do_paste(node, "copy", do_copy)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -413,17 +471,15 @@ function Clipboard:print_clipboard()
|
|||||||
end
|
end
|
||||||
|
|
||||||
---@param content string
|
---@param content string
|
||||||
function Clipboard:copy_to_reg(content)
|
---@param message? string
|
||||||
-- manually firing TextYankPost does not set vim.v.event
|
---@param opts? { notify?: boolean }
|
||||||
-- workaround: create a scratch buffer with the clipboard contents and send a yank command
|
function Clipboard:copy_to_reg(content, message, opts)
|
||||||
local temp_buf = vim.api.nvim_create_buf(false, true)
|
opts = opts and opts or {}
|
||||||
vim.api.nvim_buf_set_text(temp_buf, 0, 0, 0, 0, { content })
|
vim.fn.setreg(self.reg, type(content) == "table" and content or { content }, "v")
|
||||||
vim.api.nvim_buf_call(temp_buf, function()
|
|
||||||
vim.cmd(string.format('normal! "%sy$', self.reg))
|
|
||||||
end)
|
|
||||||
vim.api.nvim_buf_delete(temp_buf, {})
|
|
||||||
|
|
||||||
notify.info(string.format("Copied %s to %s clipboard!", content, self.clipboard_name))
|
if opts.notify ~= false then
|
||||||
|
notify.info(message or string.format("Copied %s to %s clipboard!", content, self.clipboard_name))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param node Node
|
---@param node Node
|
||||||
@@ -437,18 +493,20 @@ function Clipboard:copy_filename(node)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@private
|
||||||
---@param node Node
|
---@param node Node
|
||||||
function Clipboard:copy_basename(node)
|
---@return string
|
||||||
|
function Clipboard:get_absolute_path(node)
|
||||||
if node.name == ".." then
|
if node.name == ".." then
|
||||||
-- root
|
node = self.explorer
|
||||||
self:copy_to_reg(vim.fn.fnamemodify(self.explorer.absolute_path, ":t:r"))
|
|
||||||
else
|
|
||||||
-- node
|
|
||||||
self:copy_to_reg(vim.fn.fnamemodify(node.name, ":r"))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local absolute_path = node.absolute_path
|
||||||
|
return node.nodes ~= nil and utils.path_add_trailing(absolute_path) or absolute_path
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param node Node
|
---@param node Node
|
||||||
|
---@return string|nil
|
||||||
function Clipboard:copy_path(node)
|
function Clipboard:copy_path(node)
|
||||||
if node.name == ".." then
|
if node.name == ".." then
|
||||||
-- root
|
-- root
|
||||||
@@ -470,15 +528,44 @@ function Clipboard:copy_path(node)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param node Node
|
---@param node_or_nodes Node|Node[]
|
||||||
function Clipboard:copy_absolute_path(node)
|
---@param opts? { notify?: boolean }
|
||||||
if node.name == ".." then
|
function Clipboard:copy_absolute_path(node_or_nodes, opts)
|
||||||
node = self.explorer
|
opts = opts and opts or {}
|
||||||
|
local content
|
||||||
|
|
||||||
|
local is_single = self:is_nodes_array(node_or_nodes) == false
|
||||||
|
if is_single then
|
||||||
|
local node = #node_or_nodes == 1 and node_or_nodes[0] or node_or_nodes
|
||||||
|
content = self:get_absolute_path(node)
|
||||||
|
else
|
||||||
|
node_or_nodes = utils.filter_descendant_nodes(node_or_nodes)
|
||||||
|
content = {}
|
||||||
|
for _, node in ipairs(node_or_nodes) do
|
||||||
|
table.insert(content, self:get_absolute_path(node))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local absolute_path = node.absolute_path
|
|
||||||
local content = node.nodes ~= nil and utils.path_add_trailing(absolute_path) or absolute_path
|
if content ~= nil then
|
||||||
self:copy_to_reg(content)
|
local message = nil
|
||||||
|
|
||||||
|
if not is_single then
|
||||||
|
message = string.format("%s %s copied to register", #content, #content > 1 and "absolute paths" or "absolute path")
|
||||||
|
end
|
||||||
|
self:copy_to_reg(content, message, opts)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param node Node
|
||||||
|
function Clipboard:copy_basename(node)
|
||||||
|
if node.name == ".." then
|
||||||
|
-- root
|
||||||
|
self:copy_to_reg(vim.fn.fnamemodify(node.explorer.absolute_path, ":t:r"))
|
||||||
|
else
|
||||||
|
-- node
|
||||||
|
self:copy_to_reg(vim.fn.fnamemodify(node.name, ":r"))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---Node is cut. Will not be copied.
|
---Node is cut. Will not be copied.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
local view = require("nvim-tree.view")
|
local view = require("nvim-tree.view")
|
||||||
|
local view_state = require("nvim-tree.view-state")
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
@@ -7,7 +8,7 @@ local M = {}
|
|||||||
function M.fn(opts)
|
function M.fn(opts)
|
||||||
if opts == nil then
|
if opts == nil then
|
||||||
-- reset to config values
|
-- reset to config values
|
||||||
view.configure_width()
|
view_state.configure_width()
|
||||||
view.resize()
|
view.resize()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -16,7 +17,7 @@ function M.fn(opts)
|
|||||||
local width_cfg = options.width
|
local width_cfg = options.width
|
||||||
|
|
||||||
if width_cfg ~= nil then
|
if width_cfg ~= nil then
|
||||||
view.configure_width(width_cfg)
|
view_state.configure_width(width_cfg)
|
||||||
view.resize()
|
view.resize()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -155,14 +155,15 @@ function M.hydrate_post_setup(api)
|
|||||||
api.filter.toggle = e_(function(e) e.filters:toggle() end)
|
api.filter.toggle = e_(function(e) e.filters:toggle() end)
|
||||||
|
|
||||||
api.fs.clear_clipboard = e_(function(e) e.clipboard:clear_clipboard() end)
|
api.fs.clear_clipboard = e_(function(e) e.clipboard:clear_clipboard() end)
|
||||||
api.fs.copy.absolute_path = en(function(e, n) e.clipboard:copy_absolute_path(n) end)
|
api.fs.copy.absolute_path = ev(function(e, n) e.clipboard:copy_absolute_path(n) end)
|
||||||
api.fs.copy.basename = en(function(e, n) e.clipboard:copy_basename(n) end)
|
api.fs.copy.basename = en(function(e, n) e.clipboard:copy_basename(n) end)
|
||||||
api.fs.copy.filename = en(function(e, n) e.clipboard:copy_filename(n) end)
|
api.fs.copy.filename = en(function(e, n) e.clipboard:copy_filename(n) end)
|
||||||
api.fs.copy.node = ev(function(e, n) e.clipboard:copy(n) end)
|
|
||||||
api.fs.copy.relative_path = en(function(e, n) e.clipboard:copy_path(n) end)
|
api.fs.copy.relative_path = en(function(e, n) e.clipboard:copy_path(n) end)
|
||||||
|
api.fs.copy.node = ev(function(e, n) e.clipboard:copy(n) end)
|
||||||
api.fs.create = _n(function(n) require("nvim-tree.actions.fs.create-file").fn(n) end)
|
api.fs.create = _n(function(n) require("nvim-tree.actions.fs.create-file").fn(n) end)
|
||||||
api.fs.cut = ev(function(e, n) e.clipboard:cut(n) end)
|
api.fs.cut = ev(function(e, n) e.clipboard:cut(n) end)
|
||||||
api.fs.paste = en(function(e, n) e.clipboard:paste(n) end)
|
api.fs.paste = en(function(e, n) e.clipboard:paste(n) end)
|
||||||
|
api.fs.move = en(function(e, n) e.clipboard:paste(n, { cut = true }) end)
|
||||||
api.fs.print_clipboard = e_(function(e) e.clipboard:print_clipboard() end)
|
api.fs.print_clipboard = e_(function(e) e.clipboard:print_clipboard() end)
|
||||||
api.fs.remove = _v(function(n) require("nvim-tree.actions.fs.remove-file").fn(n) end)
|
api.fs.remove = _v(function(n) require("nvim-tree.actions.fs.remove-file").fn(n) end)
|
||||||
api.fs.rename = _n(function(n) require("nvim-tree.actions.fs.rename-file").rename_node(n) end)
|
api.fs.rename = _n(function(n) require("nvim-tree.actions.fs.rename-file").rename_node(n) end)
|
||||||
|
|||||||
@@ -17,6 +17,28 @@ function M.global()
|
|||||||
end,
|
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
|
if config.g.tab.sync.open then
|
||||||
vim.api.nvim_create_autocmd("TabEnter", {
|
vim.api.nvim_create_autocmd("TabEnter", {
|
||||||
group = augroup_id,
|
group = augroup_id,
|
||||||
|
|||||||
@@ -297,6 +297,7 @@ M.d = { -- config-default-start
|
|||||||
persist = false,
|
persist = false,
|
||||||
},
|
},
|
||||||
experimental = {
|
experimental = {
|
||||||
|
session_restore_nvim = false
|
||||||
},
|
},
|
||||||
log = {
|
log = {
|
||||||
enable = false,
|
enable = false,
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ function M.on_attach_default(bufnr)
|
|||||||
vim.keymap.set("n", "F", api.filter.live.clear, opts("Live Filter: Clear"))
|
vim.keymap.set("n", "F", api.filter.live.clear, opts("Live Filter: Clear"))
|
||||||
vim.keymap.set("n", "f", api.filter.live.start, opts("Live Filter: Start"))
|
vim.keymap.set("n", "f", api.filter.live.start, opts("Live Filter: Start"))
|
||||||
vim.keymap.set("n", "g?", api.tree.toggle_help, opts("Help"))
|
vim.keymap.set("n", "g?", api.tree.toggle_help, opts("Help"))
|
||||||
vim.keymap.set("n", "gy", api.fs.copy.absolute_path, opts("Copy Absolute Path"))
|
vim.keymap.set({ "n", "x" }, "gy", api.fs.copy.absolute_path, opts("Copy Absolute Path"))
|
||||||
vim.keymap.set("n", "ge", api.fs.copy.basename, opts("Copy Basename"))
|
vim.keymap.set("n", "ge", api.fs.copy.basename, opts("Copy Basename"))
|
||||||
vim.keymap.set("n", "H", api.filter.dotfiles.toggle, opts("Toggle Filter: Dotfiles"))
|
vim.keymap.set("n", "H", api.filter.dotfiles.toggle, opts("Toggle Filter: Dotfiles"))
|
||||||
vim.keymap.set("n", "I", api.filter.git.ignored.toggle, opts("Toggle Filter: Git Ignored"))
|
vim.keymap.set("n", "I", api.filter.git.ignored.toggle, opts("Toggle Filter: Git Ignored"))
|
||||||
@@ -102,6 +102,7 @@ function M.on_attach_default(bufnr)
|
|||||||
vim.keymap.set("n", "o", api.node.open.edit, opts("Open"))
|
vim.keymap.set("n", "o", api.node.open.edit, opts("Open"))
|
||||||
vim.keymap.set("n", "O", api.node.open.no_window_picker, opts("Open: No Window Picker"))
|
vim.keymap.set("n", "O", api.node.open.no_window_picker, opts("Open: No Window Picker"))
|
||||||
vim.keymap.set("n", "p", api.fs.paste, opts("Paste"))
|
vim.keymap.set("n", "p", api.fs.paste, opts("Paste"))
|
||||||
|
vim.keymap.set("n", "gp", api.fs.move, opts("Move"))
|
||||||
vim.keymap.set("n", "P", api.node.navigate.parent, opts("Parent Directory"))
|
vim.keymap.set("n", "P", api.node.navigate.parent, opts("Parent Directory"))
|
||||||
vim.keymap.set("n", "q", api.tree.close, opts("Close"))
|
vim.keymap.set("n", "q", api.tree.close, opts("Close"))
|
||||||
vim.keymap.set("n", "r", api.fs.rename, opts("Rename"))
|
vim.keymap.set("n", "r", api.fs.rename, opts("Rename"))
|
||||||
|
|||||||
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
|
||||||
@@ -71,7 +71,7 @@ end
|
|||||||
|
|
||||||
---Configure width-related config
|
---Configure width-related config
|
||||||
---@param width string|function|number|table|nil
|
---@param width string|function|number|table|nil
|
||||||
local function configure_width(width)
|
function M.configure_width(width)
|
||||||
if type(width) == "table" then
|
if type(width) == "table" then
|
||||||
M.Active.adaptive_size = true
|
M.Active.adaptive_size = true
|
||||||
M.Active.width = width.min or DEFAULT_MIN_WIDTH
|
M.Active.width = width.min or DEFAULT_MIN_WIDTH
|
||||||
@@ -101,7 +101,7 @@ function M.initialize()
|
|||||||
M.Active.winopts.relativenumber = config.g.view.relativenumber
|
M.Active.winopts.relativenumber = config.g.view.relativenumber
|
||||||
M.Active.winopts.signcolumn = config.g.view.signcolumn
|
M.Active.winopts.signcolumn = config.g.view.signcolumn
|
||||||
|
|
||||||
configure_width(config.g.view.width)
|
M.configure_width(config.g.view.width)
|
||||||
|
|
||||||
M.Active.initial_width = M.get_width()
|
M.Active.initial_width = M.get_width()
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ function M.resize(size)
|
|||||||
local new_size = view_state.get_width()
|
local new_size = view_state.get_width()
|
||||||
|
|
||||||
if new_size ~= vim.api.nvim_win_get_width(winnr) then
|
if new_size ~= vim.api.nvim_win_get_width(winnr) then
|
||||||
vim.api.nvim_win_set_width(winnr, new_size)
|
vim.api.nvim_win_set_width(winnr, new_size) ---@diagnostic disable-line: deprecated see #3344
|
||||||
if not config.g.view.preserve_window_proportions then
|
if not config.g.view.preserve_window_proportions then
|
||||||
vim.cmd(":wincmd =")
|
vim.cmd(":wincmd =")
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user