Skip to content

Commit 85c83cf

Browse files
committed
refactor(#2831): multi instance clipboard
1 parent e962e97 commit 85c83cf

File tree

6 files changed

+96
-70
lines changed

6 files changed

+96
-70
lines changed

lua/nvim-tree/actions/fs/copy-paste.lua

+79-49
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,43 @@ local reloaders = require "nvim-tree.actions.reloaders"
99

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

12-
local M = {
13-
config = {},
12+
---@enum ACTION
13+
local ACTION = {
14+
none = 0,
15+
copy = 1,
16+
cut = 2,
1417
}
1518

16-
local clipboard = {
17-
cut = {},
18-
copy = {},
19-
}
19+
---@class ClipboardData absolute paths
20+
---@field copy string[] copied
21+
---@field cut string[] cut
22+
23+
---@class Clipboard to handle all actions.fs clipboard API
24+
---@field config table hydrated user opts.filters
25+
---@field private explorer Explorer
26+
---@field private data ClipboardData
27+
local Clipboard = {}
28+
29+
---@param opts table user options
30+
---@param explorer Explorer
31+
---@return Clipboard
32+
function Clipboard:new(opts, explorer)
33+
local o = {
34+
explorer = explorer,
35+
data = {
36+
copy = {},
37+
cut = {},
38+
},
39+
config = {
40+
filesystem_watchers = opts.filesystem_watchers,
41+
actions = opts.actions,
42+
},
43+
}
44+
45+
setmetatable(o, self)
46+
self.__index = self
47+
return o
48+
end
2049

2150
---@param source string
2251
---@param destination string
@@ -165,37 +194,42 @@ local function toggle(node, clip)
165194
notify.info(notify_node .. " added to clipboard.")
166195
end
167196

168-
function M.clear_clipboard()
169-
clipboard.cut = {}
170-
clipboard.copy = {}
197+
---Clear copied and cut
198+
function Clipboard:clear_clipboard()
199+
self.data.cut = {}
200+
self.data.copy = {}
171201
notify.info "Clipboard has been emptied."
172202
renderer.draw()
173203
end
174204

205+
---Copy one node
175206
---@param node Node
176-
function M.copy(node)
177-
utils.array_remove(clipboard.cut, node)
178-
toggle(node, clipboard.copy)
207+
function Clipboard:copy(node)
208+
utils.array_remove(self.data.cut, node)
209+
toggle(node, self.data.copy)
179210
renderer.draw()
180211
end
181212

213+
---Cut one node
182214
---@param node Node
183-
function M.cut(node)
184-
utils.array_remove(clipboard.copy, node)
185-
toggle(node, clipboard.cut)
215+
function Clipboard:cut(node)
216+
utils.array_remove(self.data.copy, node)
217+
toggle(node, self.data.cut)
186218
renderer.draw()
187219
end
188220

221+
---Paste cut or cop
222+
---@private
189223
---@param node Node
190224
---@param action_type string
191225
---@param action_fn fun(source: string, dest: string)
192-
local function do_paste(node, action_type, action_fn)
226+
function Clipboard:do_paste(node, action_type, action_fn)
193227
node = lib.get_last_group_node(node)
194228
local explorer = core.get_explorer()
195229
if node.name == ".." and explorer then
196230
node = explorer
197231
end
198-
local clip = clipboard[action_type]
232+
local clip = self.data[action_type]
199233
if #clip == 0 then
200234
return
201235
end
@@ -217,8 +251,8 @@ local function do_paste(node, action_type, action_fn)
217251
do_single_paste(_node.absolute_path, dest, action_type, action_fn)
218252
end
219253

220-
clipboard[action_type] = {}
221-
if not M.config.filesystem_watchers.enable then
254+
self.data[action_type] = {}
255+
if not self.config.filesystem_watchers.enable then
222256
reloaders.reload_explorer()
223257
end
224258
end
@@ -246,26 +280,27 @@ local function do_cut(source, destination)
246280
return true
247281
end
248282

283+
---Paste cut (if present) or copy (if present)
249284
---@param node Node
250-
function M.paste(node)
251-
if clipboard.cut[1] ~= nil then
252-
do_paste(node, "cut", do_cut)
253-
else
254-
do_paste(node, "copy", do_copy)
285+
function Clipboard:paste(node)
286+
if self.data.cut[1] ~= nil then
287+
self:do_paste(node, "cut", do_cut)
288+
elseif self.data.copy[1] ~= nil then
289+
self:do_paste(node, "cop", do_copy)
255290
end
256291
end
257292

258-
function M.print_clipboard()
293+
function Clipboard:print_clipboard()
259294
local content = {}
260-
if #clipboard.cut > 0 then
295+
if #self.data.cut > 0 then
261296
table.insert(content, "Cut")
262-
for _, node in pairs(clipboard.cut) do
297+
for _, node in pairs(self.data.cut) do
263298
table.insert(content, " * " .. (notify.render_path(node.absolute_path)))
264299
end
265300
end
266-
if #clipboard.copy > 0 then
301+
if #self.data.copy > 0 then
267302
table.insert(content, "Copy")
268-
for _, node in pairs(clipboard.copy) do
303+
for _, node in pairs(self.data.copy) do
269304
table.insert(content, " * " .. (notify.render_path(node.absolute_path)))
270305
end
271306
end
@@ -274,10 +309,10 @@ function M.print_clipboard()
274309
end
275310

276311
---@param content string
277-
local function copy_to_clipboard(content)
312+
function Clipboard:copy_to_clipboard(content)
278313
local clipboard_name
279314
local reg
280-
if M.config.actions.use_system_clipboard == true then
315+
if self.config.actions.use_system_clipboard == true then
281316
clipboard_name = "system"
282317
reg = "+"
283318
else
@@ -298,18 +333,18 @@ local function copy_to_clipboard(content)
298333
end
299334

300335
---@param node Node
301-
function M.copy_filename(node)
302-
copy_to_clipboard(node.name)
336+
function Clipboard:copy_filename(node)
337+
self:copy_to_clipboard(node.name)
303338
end
304339

305340
---@param node Node
306-
function M.copy_basename(node)
341+
function Clipboard:copy_basename(node)
307342
local basename = vim.fn.fnamemodify(node.name, ":r")
308-
copy_to_clipboard(basename)
343+
self:copy_to_clipboard(basename)
309344
end
310345

311346
---@param node Node
312-
function M.copy_path(node)
347+
function Clipboard:copy_path(node)
313348
local absolute_path = node.absolute_path
314349
local cwd = core.get_cwd()
315350
if cwd == nil then
@@ -318,33 +353,28 @@ function M.copy_path(node)
318353

319354
local relative_path = utils.path_relative(absolute_path, cwd)
320355
local content = node.nodes ~= nil and utils.path_add_trailing(relative_path) or relative_path
321-
copy_to_clipboard(content)
356+
self:copy_to_clipboard(content)
322357
end
323358

324359
---@param node Node
325-
function M.copy_absolute_path(node)
360+
function Clipboard:copy_absolute_path(node)
326361
local absolute_path = node.absolute_path
327362
local content = node.nodes ~= nil and utils.path_add_trailing(absolute_path) or absolute_path
328-
copy_to_clipboard(content)
363+
self:copy_to_clipboard(content)
329364
end
330365

331366
---Node is cut. Will not be copied.
332367
---@param node Node
333368
---@return boolean
334-
function M.is_cut(node)
335-
return vim.tbl_contains(clipboard.cut, node)
369+
function Clipboard:is_cut(node)
370+
return vim.tbl_contains(self.data.cut, node)
336371
end
337372

338373
---Node is copied. Will not be cut.
339374
---@param node Node
340375
---@return boolean
341-
function M.is_copied(node)
342-
return vim.tbl_contains(clipboard.copy, node)
343-
end
344-
345-
function M.setup(opts)
346-
M.config.filesystem_watchers = opts.filesystem_watchers
347-
M.config.actions = opts.actions
376+
function Clipboard:is_copied(node)
377+
return vim.tbl_contains(self.data.copy, node)
348378
end
349379

350-
return M
380+
return Clipboard

lua/nvim-tree/actions/fs/init.lua

-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
local M = {}
22

3-
M.copy_paste = require "nvim-tree.actions.fs.copy-paste"
43
M.create_file = require "nvim-tree.actions.fs.create-file"
54
M.remove_file = require "nvim-tree.actions.fs.remove-file"
65
M.rename_file = require "nvim-tree.actions.fs.rename-file"
76
M.trash = require "nvim-tree.actions.fs.trash"
87

98
function M.setup(opts)
10-
M.copy_paste.setup(opts)
119
M.remove_file.setup(opts)
1210
M.rename_file.setup(opts)
1311
M.trash.setup(opts)

lua/nvim-tree/api.lua

+9-9
Original file line numberDiff line numberDiff line change
@@ -174,15 +174,15 @@ Api.fs.rename = wrap_node(actions.fs.rename_file.fn ":t")
174174
Api.fs.rename_sub = wrap_node(actions.fs.rename_file.fn ":p:h")
175175
Api.fs.rename_basename = wrap_node(actions.fs.rename_file.fn ":t:r")
176176
Api.fs.rename_full = wrap_node(actions.fs.rename_file.fn ":p")
177-
Api.fs.cut = wrap_node(actions.fs.copy_paste.cut)
178-
Api.fs.paste = wrap_node(actions.fs.copy_paste.paste)
179-
Api.fs.clear_clipboard = wrap(actions.fs.copy_paste.clear_clipboard)
180-
Api.fs.print_clipboard = wrap(actions.fs.copy_paste.print_clipboard)
181-
Api.fs.copy.node = wrap_node(actions.fs.copy_paste.copy)
182-
Api.fs.copy.absolute_path = wrap_node(actions.fs.copy_paste.copy_absolute_path)
183-
Api.fs.copy.filename = wrap_node(actions.fs.copy_paste.copy_filename)
184-
Api.fs.copy.basename = wrap_node(actions.fs.copy_paste.copy_basename)
185-
Api.fs.copy.relative_path = wrap_node(actions.fs.copy_paste.copy_path)
177+
Api.fs.cut = wrap_node(wrap_explorer_member("clipboard", "cut"))
178+
Api.fs.paste = wrap_node(wrap_explorer_member("clipboard", "paste"))
179+
Api.fs.clear_clipboard = wrap_explorer_member("clipboard", "clear_clipboard")
180+
Api.fs.print_clipboard = wrap_explorer_member("clipboard", "print_clipboard")
181+
Api.fs.copy.node = wrap_node(wrap_explorer_member("clipboard", "copy"))
182+
Api.fs.copy.absolute_path = wrap_node(wrap_explorer_member("clipboard", "copy_absolute_path"))
183+
Api.fs.copy.filename = wrap_node(wrap_explorer_member("clipboard", "copy_filename"))
184+
Api.fs.copy.basename = wrap_node(wrap_explorer_member("clipboard", "copy_basename"))
185+
Api.fs.copy.relative_path = wrap_node(wrap_explorer_member("clipboard", "copy_path"))
186186

187187
---@param mode string
188188
---@param node table

lua/nvim-tree/explorer/init.lua

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ local Filters = require "nvim-tree.explorer.filters"
66
local Marks = {} -- circular dependencies
77
local LiveFilter = require "nvim-tree.explorer.live-filter"
88
local Sorters = require "nvim-tree.explorer.sorters"
9+
local Clipboard = {} -- circular dependencies
910

1011
local M = {}
1112

@@ -20,6 +21,7 @@ M.reload = require("nvim-tree.explorer.reload").reload
2021
---@field live_filter LiveFilter
2122
---@field sorters Sorter
2223
---@field marks Marks
24+
---@field clipboard Clipboard
2325

2426
local Explorer = {}
2527
Explorer.__index = Explorer
@@ -50,6 +52,7 @@ function Explorer.new(path)
5052
explorer.filters = Filters:new(M.config, explorer)
5153
explorer.live_filter = LiveFilter:new(M.config, explorer)
5254
explorer.marks = Marks:new(M.config, explorer)
55+
explorer.clipboard = Clipboard:new(M.config, explorer)
5356
explorer:_load(explorer)
5457
return explorer
5558
end
@@ -87,6 +90,7 @@ function M.setup(opts)
8790
require("nvim-tree.explorer.watch").setup(opts)
8891

8992
Marks = require "nvim-tree.marks"
93+
Clipboard = require "nvim-tree.actions.fs.clipboard"
9094
end
9195

9296
M.Explorer = Explorer

lua/nvim-tree/renderer/decorator/copied.lua

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
local copy_paste
1+
local core = require "nvim-tree.core"
22

33
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
44
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
@@ -20,17 +20,14 @@ function DecoratorCopied:new(opts)
2020
})
2121
---@cast o DecoratorCopied
2222

23-
-- cyclic
24-
copy_paste = copy_paste or require "nvim-tree.actions.fs.copy-paste"
25-
2623
return o
2724
end
2825

2926
---Copied highlight: renderer.highlight_clipboard and node is copied
3027
---@param node Node
3128
---@return string|nil group
3229
function DecoratorCopied:calculate_highlight(node)
33-
if self.hl_pos ~= HL_POSITION.none and copy_paste.is_copied(node) then
30+
if self.hl_pos ~= HL_POSITION.none and core.get_explorer() and core.get_explorer().clipboard:is_copied(node) then
3431
return "NvimTreeCopiedHL"
3532
end
3633
end

lua/nvim-tree/renderer/decorator/cut.lua

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
local copy_paste
1+
local core = require "nvim-tree.core"
22

33
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
44
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
@@ -20,17 +20,14 @@ function DecoratorCut:new(opts)
2020
})
2121
---@cast o DecoratorCut
2222

23-
-- cyclic
24-
copy_paste = copy_paste or require "nvim-tree.actions.fs.copy-paste"
25-
2623
return o
2724
end
2825

2926
---Cut highlight: renderer.highlight_clipboard and node is cut
3027
---@param node Node
3128
---@return string|nil group
3229
function DecoratorCut:calculate_highlight(node)
33-
if self.hl_pos ~= HL_POSITION.none and copy_paste.is_cut(node) then
30+
if self.hl_pos ~= HL_POSITION.none and core.get_explorer() and core.get_explorer().clipboard:is_cut(node) then
3431
return "NvimTreeCutHL"
3532
end
3633
end

0 commit comments

Comments
 (0)