-
-
Notifications
You must be signed in to change notification settings - Fork 635
feat(#1549): copy files between multiple nvim instances #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 all 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
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" | ||
|
|
@@ -176,28 +177,40 @@ 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) | ||
| 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() | ||
| else | ||
| self:bulk_clipboard(utils.filter_descendant_nodes(node_or_nodes), self.data.cut, self.data.copy, "added to") | ||
| end | ||
| self:copy_node_attribute(node_or_nodes, "absolute_path", { notify = false }) | ||
| 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() | ||
| else | ||
| self:bulk_clipboard(utils.filter_descendant_nodes(node_or_nodes), self.data.copy, self.data.cut, "cut to") | ||
| end | ||
| self:copy_node_attribute(node_or_nodes, "absolute_path", { notify = false }) | ||
| end | ||
|
|
||
| ---Clear clipboard for action and reload to reflect filesystem changes from paste. | ||
|
|
@@ -304,6 +317,30 @@ 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), "\n") | ||
|
|
||
| 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)) | ||
| else | ||
| table.insert(nodes, FileNode(node_args)) | ||
| end | ||
| end | ||
| return nodes | ||
| end | ||
|
|
||
| ---Paste cut or copy with batch conflict resolution. | ||
| ---@private | ||
| ---@param node Node | ||
|
|
@@ -318,7 +355,8 @@ function Clipboard:do_paste(node, action, action_fn) | |
| node = dir:last_group_node() | ||
| end | ||
| end | ||
| local clip = self.data[action] | ||
| local clip = #self.data[action] > 0 and self.data[action] or self:get_nodes_from_reg() | ||
|
|
||
| if #clip == 0 then | ||
| return | ||
| end | ||
|
|
@@ -386,10 +424,12 @@ end | |
|
|
||
| ---Paste cut (if present) or copy (if present) | ||
| ---@param node Node | ||
| function Clipboard:paste(node) | ||
| if self.data.cut[1] ~= nil then | ||
| ---@param opts? { cut?: boolean } | ||
| 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) | ||
| elseif self.data.copy[1] ~= nil then | ||
| else | ||
| self:do_paste(node, "copy", do_copy) | ||
| end | ||
| end | ||
|
|
@@ -413,46 +453,73 @@ function Clipboard:print_clipboard() | |
| end | ||
|
|
||
| ---@param content string | ||
| function Clipboard:copy_to_reg(content) | ||
| -- 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) | ||
| vim.api.nvim_buf_set_text(temp_buf, 0, 0, 0, 0, { content }) | ||
| 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)) | ||
| ---@param message? string | ||
| ---@param opts? { notify?: boolean } | ||
| function Clipboard:copy_to_reg(content, message, opts) | ||
| opts = opts and opts or {} | ||
| vim.fn.setreg(self.reg, type(content) == "table" and content or { content }, "v") | ||
|
|
||
| if opts.notify ~= false then | ||
| notify.info(message or string.format("Copied %s to %s clipboard!", content, self.clipboard_name)) | ||
| end | ||
| end | ||
|
|
||
| ---@param node Node | ||
| function Clipboard:copy_filename(node) | ||
| ---@return string | ||
| function Clipboard:get_node_filename(node) | ||
| if node.name == ".." then | ||
| -- root | ||
| self:copy_to_reg(vim.fn.fnamemodify(self.explorer.absolute_path, ":t")) | ||
| return vim.fn.fnamemodify(self.explorer.absolute_path, ":t") | ||
| else | ||
| -- node | ||
| self:copy_to_reg(node.name) | ||
| return node.name | ||
| 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[] | ||
| ---@param attribute "absolute_path" | "basename" | "filename" | "relative_path" | ||
| ---@param opts? { notify?: boolean } | ||
| function Clipboard:copy_node_attribute(node_or_nodes, attribute, opts) | ||
| opts = opts and opts or {} | ||
| local content | ||
| local node_attribute_getters = { | ||
| basename = function(n) return self:get_node_basename(n) end, | ||
| filename = function(n) return self:get_node_filename(n) end, | ||
| relative_path = function(n) return self:get_node_relative_path(n) end, | ||
| absolute_path = function(n) return self:get_node_absolute_path(n) end, | ||
| } | ||
|
Comment on lines
+485
to
+490
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 really appreciate the care and effort you've made with this refactor, however:
Let's limit the scope of this change to the minimum required to achieve the functionality: atomic changes.
I'm always open to refactors and polishing, however please raise separate PRs for them. |
||
|
|
||
| local attribute_getter = node_attribute_getters[attribute] | ||
|
|
||
| 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 = attribute_getter(node) | ||
| else | ||
| -- node | ||
| self:copy_to_reg(vim.fn.fnamemodify(node.name, ":r")) | ||
| node_or_nodes = utils.filter_descendant_nodes(node_or_nodes) | ||
| content = {} | ||
| for _, node in ipairs(node_or_nodes) do | ||
| table.insert(content, attribute_getter(node)) | ||
| end | ||
| end | ||
|
|
||
|
|
||
| if content ~= nil then | ||
| local message = nil | ||
|
|
||
| if not is_single then | ||
| message = string.format("%s %s copied to register", #content, attribute:gsub("_", " ") .. "s") | ||
| end | ||
| self:copy_to_reg(content, message, opts) | ||
| end | ||
| end | ||
|
|
||
| ---@param node Node | ||
| function Clipboard:copy_path(node) | ||
| ---@return string|nil | ||
| function Clipboard:get_node_relative_path(node) | ||
| if node.name == ".." then | ||
| -- root | ||
| self:copy_to_reg(utils.path_add_trailing("")) | ||
| return utils.path_add_trailing("") | ||
| else | ||
| -- node | ||
| local absolute_path = node.absolute_path | ||
|
|
@@ -463,22 +530,35 @@ function Clipboard:copy_path(node) | |
|
|
||
| local relative_path = utils.path_relative(absolute_path, cwd) | ||
| if node:is(DirectoryNode) then | ||
| self:copy_to_reg(utils.path_add_trailing(relative_path)) | ||
| return utils.path_add_trailing(relative_path) | ||
| else | ||
| self:copy_to_reg(relative_path) | ||
| return relative_path | ||
| end | ||
| end | ||
| end | ||
|
|
||
| ---@private | ||
| ---@param node Node | ||
| function Clipboard:copy_absolute_path(node) | ||
| ---@return string | ||
| function Clipboard:get_node_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 Node | ||
| ---@return string | ||
| function Clipboard:get_node_basename(node) | ||
| if node.name == ".." then | ||
| -- root | ||
| return vim.fn.fnamemodify(node.explorer.absolute_path, ":t:r") | ||
| else | ||
| -- node | ||
| return vim.fn.fnamemodify(node.name, ":r") | ||
| end | ||
| end | ||
|
|
||
| ---Node is cut. Will not be copied. | ||
|
|
||
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 :)