-
-
Notifications
You must be signed in to change notification settings - Fork 634
feat(#1549): p will paste files from another nvim-tree instance, gp will cut/paste #3336
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 18 commits
ddbc033
c842a08
058e508
89edce6
b98e0c4
f2269a1
cdc7b28
38ada46
b9e9b7a
877e726
885b4d9
2c56cc6
77325e5
a9253de
0fd8cfa
073fac1
27f5254
43f01b5
4f787e0
a7e647b
ba8e7a1
f79cdcb
356c083
6f1b818
887e6c1
859f733
b1662a5
5eba88e
fa2b186
4bd13ec
062a2d2
f10f779
30c5036
1b67371
4fcbafe
4b13775
cb58a07
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,8 +24,6 @@ error("Cannot require a meta file") | |
| ---[nvim_tree.config.actions.remove_file] | ||
| ---@field remove_file? nvim_tree.config.actions.remove_file | ||
|
|
||
|
|
||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm guessing the style tooling fixed this. |
||
| --- vim [current-directory] behaviour | ||
| ---@class nvim_tree.config.actions.change_dir | ||
| --- | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,7 @@ local find_file = require("nvim-tree.actions.finders.find-file").fn | |
|
|
||
| local Class = require("nvim-tree.classic") | ||
| local DirectoryNode = require("nvim-tree.node.directory") | ||
| local FileNode = require("nvim-tree.node.file") | ||
| local Node = require("nvim-tree.node") | ||
|
|
||
| ---@alias ClipboardAction "copy" | "cut" | ||
|
|
@@ -43,6 +44,10 @@ function Clipboard:new(args) | |
| self.reg = self.explorer.opts.actions.use_system_clipboard and "+" or "1" | ||
| end | ||
|
|
||
| ---@class PasteOptions | ||
| ---@field use_register? boolean | ||
| ---@field cut? boolean | ||
|
|
||
| ---@param source string | ||
| ---@param destination string | ||
| ---@return boolean | ||
|
|
@@ -176,10 +181,20 @@ function Clipboard:bulk_clipboard(nodes, from, to, verb) | |
| self.explorer.renderer:draw() | ||
| end | ||
|
|
||
| ---@private | ||
| ---@param node_or_nodes Node|Node[] | ||
| ---@return boolean | ||
| function Clipboard:is_nodes_array(node_or_nodes) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was pretty hard on you about the This refactor is good as it is necessary to avoid (already) duplicated code for the new feature.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was exactly the purpose of the refactor, that's why I did it. maybe we can do it on the future. |
||
| 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 | ||
| ---@param node_or_nodes Node|Node[] | ||
| 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) | ||
| toggle(node_or_nodes, self.data.copy) | ||
| self.explorer.renderer:draw() | ||
|
|
@@ -191,7 +206,7 @@ end | |
| ---Cut one or more nodes | ||
| ---@param node_or_nodes Node|Node[] | ||
| 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) | ||
| toggle(node_or_nodes, self.data.cut) | ||
| self.explorer.renderer:draw() | ||
|
|
@@ -304,12 +319,37 @@ function Clipboard:resolve_conflicts(conflict, destination, action, action_fn) | |
| 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), ",") | ||
|
|
||
| for _, absolute_path in ipairs(absolute_paths) do | ||
| 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)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Creating (dummy) nodes is a smart way to work with the existing clipboard code to avoid massive changes. We do need to destroy They are mixed in with current instance nodes in the Suggestion: keep the dummy nodes from
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I called destroy to everything on the clip variable itself and everything looks fine. |
||
| else | ||
| table.insert(nodes, FileNode(node_args)) | ||
| end | ||
| end | ||
| return nodes | ||
| end | ||
|
|
||
| ---Paste cut or copy with batch conflict resolution. | ||
| ---@private | ||
| ---@param node Node | ||
| ---@param action ClipboardAction | ||
| ---@param action_fn ClipboardActionFn | ||
| function Clipboard:do_paste(node, action, action_fn) | ||
| ---@param opts? PasteOptions | ||
| function Clipboard:do_paste(node, action, action_fn, opts) | ||
| if node.name == ".." then | ||
| node = self.explorer | ||
| else | ||
|
|
@@ -318,7 +358,7 @@ function Clipboard:do_paste(node, action, action_fn) | |
| node = dir:last_group_node() | ||
| end | ||
| end | ||
| local clip = self.data[action] | ||
| local clip = opts and opts.use_register and self:get_nodes_from_reg() or self.data[action] | ||
| if #clip == 0 then | ||
| return | ||
| end | ||
|
|
@@ -386,11 +426,12 @@ end | |
|
|
||
| ---Paste cut (if present) or copy (if present) | ||
| ---@param node Node | ||
| function Clipboard:paste(node) | ||
| if self.data.cut[1] ~= nil then | ||
| self:do_paste(node, "cut", do_cut) | ||
| elseif self.data.copy[1] ~= nil then | ||
| self:do_paste(node, "copy", do_copy) | ||
| ---@param opts? PasteOptions | ||
| function Clipboard:paste(node, opts) | ||
| if self.data.cut[1] ~= nil or opts and opts.use_register and opts.cut then | ||
| self:do_paste(node, "cut", do_cut, opts) | ||
| elseif self.data.copy[1] ~= nil or opts and opts.use_register then | ||
| self:do_paste(node, "copy", do_copy, opts) | ||
| end | ||
| end | ||
|
|
||
|
|
@@ -413,7 +454,8 @@ function Clipboard:print_clipboard() | |
| end | ||
|
|
||
| ---@param content string | ||
| function Clipboard:copy_to_reg(content) | ||
| ---@param msg? string | ||
| function Clipboard:copy_to_reg(content, msg) | ||
| -- manually firing TextYankPost does not set vim.v.event | ||
| -- workaround: create a scratch buffer with the clipboard contents and send a yank command | ||
| local temp_buf = vim.api.nvim_create_buf(false, true) | ||
|
|
@@ -423,7 +465,7 @@ function Clipboard:copy_to_reg(content) | |
| end) | ||
| vim.api.nvim_buf_delete(temp_buf, {}) | ||
|
|
||
| notify.info(string.format("Copied %s to %s clipboard!", content, self.clipboard_name)) | ||
| notify.info(msg or string.format("Copied %s to %s clipboard!", content, self.clipboard_name)) | ||
| end | ||
|
|
||
| ---@param node Node | ||
|
|
@@ -437,15 +479,22 @@ function Clipboard:copy_filename(node) | |
| end | ||
| end | ||
|
|
||
| ---@param node Node | ||
| function Clipboard:copy_basename(node) | ||
| if node.name == ".." then | ||
| -- root | ||
| self:copy_to_reg(vim.fn.fnamemodify(self.explorer.absolute_path, ":t:r")) | ||
| ---@param node_or_nodes Node|Node[] | ||
| function Clipboard:copy_basename(node_or_nodes) | ||
| local content = "" | ||
| if self:is_nodes_array(node_or_nodes) == false or #node_or_nodes == 1 then | ||
| local node = #node_or_nodes == 1 and node_or_nodes[0] or node_or_nodes | ||
| content = node:get_basename() | ||
| else | ||
| -- node | ||
| self:copy_to_reg(vim.fn.fnamemodify(node.name, ":r")) | ||
| for i, node in ipairs(node_or_nodes) do | ||
| if i == 1 then | ||
| content = node:get_basename() | ||
| else | ||
| content = content .. "," .. node:get_basename() | ||
| end | ||
| end | ||
| end | ||
| self:copy_to_reg(content) | ||
| end | ||
|
|
||
| ---@param node Node | ||
|
|
@@ -470,15 +519,37 @@ function Clipboard:copy_path(node) | |
| end | ||
| end | ||
|
|
||
| ---@private | ||
| ---@param node Node | ||
| function Clipboard:copy_absolute_path(node) | ||
| ---@return string | ||
| function Clipboard:get_absolute_path(node) | ||
| if node.name == ".." then | ||
| node = self.explorer | ||
| end | ||
|
|
||
| local absolute_path = node.absolute_path | ||
| local content = node.nodes ~= nil and utils.path_add_trailing(absolute_path) or absolute_path | ||
| self:copy_to_reg(content) | ||
| return node.nodes ~= nil and utils.path_add_trailing(absolute_path) or absolute_path | ||
| end | ||
|
|
||
| ---@param node_or_nodes Node|Node[] | ||
| function Clipboard:copy_absolute_path(node_or_nodes) | ||
| local content = "" | ||
| local is_single = self:is_nodes_array(node_or_nodes) == false or #node_or_nodes == 1 | ||
| 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) | ||
| for i, node in ipairs(node_or_nodes) do | ||
| if i == 1 then | ||
| content = self:get_absolute_path(node) | ||
| else | ||
| content = content .. "," .. self:get_absolute_path(node) | ||
| end | ||
| end | ||
| end | ||
|
|
||
| self:copy_to_reg(content, string.format("%s paths copied to register", is_single and 1 or #node_or_nodes)) | ||
| end | ||
|
|
||
| ---Node is cut. Will not be copied. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -159,4 +159,14 @@ function Node:expand(expand_opts) | |
| end | ||
| end | ||
|
|
||
| function Node:get_basename() | ||
| if self.name == ".." then | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On further reflection, changing the Let's keep it localised - please move this method to |
||
| -- root | ||
| return vim.fn.fnamemodify(self.explorer.absolute_path, ":t:r") | ||
| else | ||
| -- node | ||
| return vim.fn.fnamemodify(self.name, ":r") | ||
| end | ||
| end | ||
|
|
||
| return Node | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still need these two? They don't appear to be used.
pdoes the job now :)