@@ -9,31 +9,34 @@ local find_file = require("nvim-tree.actions.finders.find-file").fn
99
1010local DirectoryNode = require (" nvim-tree.node.directory" )
1111
12- --- @enum ACTION
13- local ACTION = {
14- copy = " copy" ,
15- cut = " cut" ,
16- }
12+ --- @alias ClipboardAction " copy" | " cut"
13+ --- @alias ClipboardData table<ClipboardAction , Node[]>
14+
15+ --- @alias ClipboardActionFn fun ( source : string , dest : string ): boolean , string ?
1716
1817--- @class Clipboard to handle all actions.fs clipboard API
1918--- @field config table hydrated user opts.filters
2019--- @field private explorer Explorer
21- --- @field private data table<ACTION , Node[]>
20+ --- @field private data ClipboardData
21+ --- @field private clipboard_name string
22+ --- @field private reg string
2223local Clipboard = {}
2324
2425--- @param opts table user options
2526--- @param explorer Explorer
2627--- @return Clipboard
2728function Clipboard :new (opts , explorer )
29+ --- @type Clipboard
2830 local o = {
2931 explorer = explorer ,
3032 data = {
31- [ ACTION . copy ] = {},
32- [ ACTION . cut ] = {},
33+ copy = {},
34+ cut = {},
3335 },
36+ clipboard_name = opts .actions .use_system_clipboard and " system" or " neovim" ,
37+ reg = opts .actions .use_system_clipboard and " +" or " 1" ,
3438 config = {
3539 filesystem_watchers = opts .filesystem_watchers ,
36- actions = opts .actions ,
3740 },
3841 }
3942
4750--- @return boolean
4851--- @return string | nil
4952local function do_copy (source , destination )
50- local source_stats , handle
51- local success , errmsg
53+ local source_stats , err = vim .loop .fs_stat (source )
5254
53- source_stats , errmsg = vim .loop .fs_stat (source )
5455 if not source_stats then
55- log .line (" copy_paste" , " do_copy fs_stat '%s' failed '%s'" , source , errmsg )
56- return false , errmsg
56+ log .line (" copy_paste" , " do_copy fs_stat '%s' failed '%s'" , source , err )
57+ return false , err
5758 end
5859
5960 log .line (" copy_paste" , " do_copy %s '%s' -> '%s'" , source_stats .type , source , destination )
@@ -64,25 +65,28 @@ local function do_copy(source, destination)
6465 end
6566
6667 if source_stats .type == " file" then
67- success , errmsg = vim .loop .fs_copyfile (source , destination )
68+ local success
69+ success , err = vim .loop .fs_copyfile (source , destination )
6870 if not success then
69- log .line (" copy_paste" , " do_copy fs_copyfile failed '%s'" , errmsg )
70- return false , errmsg
71+ log .line (" copy_paste" , " do_copy fs_copyfile failed '%s'" , err )
72+ return false , err
7173 end
7274 return true
7375 elseif source_stats .type == " directory" then
74- handle , errmsg = vim .loop .fs_scandir (source )
76+ local handle
77+ handle , err = vim .loop .fs_scandir (source )
7578 if type (handle ) == " string" then
7679 return false , handle
7780 elseif not handle then
78- log .line (" copy_paste" , " do_copy fs_scandir '%s' failed '%s'" , source , errmsg )
79- return false , errmsg
81+ log .line (" copy_paste" , " do_copy fs_scandir '%s' failed '%s'" , source , err )
82+ return false , err
8083 end
8184
82- success , errmsg = vim .loop .fs_mkdir (destination , source_stats .mode )
85+ local success
86+ success , err = vim .loop .fs_mkdir (destination , source_stats .mode )
8387 if not success then
84- log .line (" copy_paste" , " do_copy fs_mkdir '%s' failed '%s'" , destination , errmsg )
85- return false , errmsg
88+ log .line (" copy_paste" , " do_copy fs_mkdir '%s' failed '%s'" , destination , err )
89+ return false , err
8690 end
8791
8892 while true do
@@ -93,44 +97,42 @@ local function do_copy(source, destination)
9397
9498 local new_name = utils .path_join ({ source , name })
9599 local new_destination = utils .path_join ({ destination , name })
96- success , errmsg = do_copy (new_name , new_destination )
100+ success , err = do_copy (new_name , new_destination )
97101 if not success then
98- return false , errmsg
102+ return false , err
99103 end
100104 end
101105 else
102- errmsg = string.format (" '%s' illegal file type '%s'" , source , source_stats .type )
103- log .line (" copy_paste" , " do_copy %s" , errmsg )
104- return false , errmsg
106+ err = string.format (" '%s' illegal file type '%s'" , source , source_stats .type )
107+ log .line (" copy_paste" , " do_copy %s" , err )
108+ return false , err
105109 end
106110
107111 return true
108112end
109113
110114--- @param source string
111115--- @param dest string
112- --- @param action ACTION
113- --- @param action_fn fun ( source : string , dest : string )
116+ --- @param action ClipboardAction
117+ --- @param action_fn ClipboardActionFn
114118--- @return boolean | nil -- success
115119--- @return string | nil -- error message
116120local function do_single_paste (source , dest , action , action_fn )
117- local dest_stats
118- local success , errmsg , errcode
119121 local notify_source = notify .render_path (source )
120122
121123 log .line (" copy_paste" , " do_single_paste '%s' -> '%s'" , source , dest )
122124
123- dest_stats , errmsg , errcode = vim .loop .fs_stat (dest )
124- if not dest_stats and errcode ~= " ENOENT" then
125- notify .error (" Could not " .. action .. " " .. notify_source .. " - " .. (errmsg or " ???" ))
126- return false , errmsg
125+ local dest_stats , err , err_name = vim .loop .fs_stat (dest )
126+ if not dest_stats and err_name ~= " ENOENT" then
127+ notify .error (" Could not " .. action .. " " .. notify_source .. " - " .. (err or " ???" ))
128+ return false , err
127129 end
128130
129131 local function on_process ()
130- success , errmsg = action_fn (source , dest )
132+ local success , error = action_fn (source , dest )
131133 if not success then
132- notify .error (" Could not " .. action .. " " .. notify_source .. " - " .. (errmsg or " ???" ))
133- return false , errmsg
134+ notify .error (" Could not " .. action .. " " .. notify_source .. " - " .. (error or " ???" ))
135+ return false , error
134136 end
135137
136138 find_file (utils .path_remove_trailing (dest ))
@@ -173,7 +175,7 @@ local function do_single_paste(source, dest, action, action_fn)
173175end
174176
175177--- @param node Node
176- --- @param clip table
178+ --- @param clip ClipboardData
177179local function toggle (node , clip )
178180 if node .name == " .." then
179181 return
@@ -191,49 +193,52 @@ end
191193
192194--- Clear copied and cut
193195function Clipboard :clear_clipboard ()
194- self .data [ ACTION .copy ] = {}
195- self .data [ ACTION .cut ] = {}
196+ self .data .copy = {}
197+ self .data .cut = {}
196198 notify .info (" Clipboard has been emptied." )
197199 self .explorer .renderer :draw ()
198200end
199201
200202--- Copy one node
201203--- @param node Node
202204function Clipboard :copy (node )
203- utils .array_remove (self .data [ ACTION .cut ] , node )
204- toggle (node , self .data [ ACTION .copy ] )
205+ utils .array_remove (self .data .cut , node )
206+ toggle (node , self .data .copy )
205207 self .explorer .renderer :draw ()
206208end
207209
208210--- Cut one node
209211--- @param node Node
210212function Clipboard :cut (node )
211- utils .array_remove (self .data [ ACTION .copy ] , node )
212- toggle (node , self .data [ ACTION .cut ] )
213+ utils .array_remove (self .data .copy , node )
214+ toggle (node , self .data .cut )
213215 self .explorer .renderer :draw ()
214216end
215217
216218--- Paste cut or cop
217219--- @private
218220--- @param node Node
219- --- @param action ACTION
220- --- @param action_fn fun ( source : string , dest : string )
221+ --- @param action ClipboardAction
222+ --- @param action_fn ClipboardActionFn
221223function Clipboard :do_paste (node , action , action_fn )
222224 if node .name == " .." then
223225 node = self .explorer
224- elseif node :is (DirectoryNode ) then
225- node = node :last_group_node ()
226+ else
227+ local dir = node :as (DirectoryNode )
228+ if dir then
229+ node = dir :last_group_node ()
230+ end
226231 end
227232 local clip = self .data [action ]
228233 if # clip == 0 then
229234 return
230235 end
231236
232237 local destination = node .absolute_path
233- local stats , errmsg , errcode = vim .loop .fs_stat (destination )
234- if not stats and errcode ~= " ENOENT" then
235- log .line (" copy_paste" , " do_paste fs_stat '%s' failed '%s'" , destination , errmsg )
236- notify .error (" Could not " .. action .. " " .. notify .render_path (destination ) .. " - " .. (errmsg or " ???" ))
238+ local stats , err , err_name = vim .loop .fs_stat (destination )
239+ if not stats and err_name ~= " ENOENT" then
240+ log .line (" copy_paste" , " do_paste fs_stat '%s' failed '%s'" , destination , err )
241+ notify .error (" Could not " .. action .. " " .. notify .render_path (destination ) .. " - " .. (err or " ???" ))
237242 return
238243 end
239244 local is_dir = stats and stats .type == " directory"
@@ -278,24 +283,24 @@ end
278283--- Paste cut (if present) or copy (if present)
279284--- @param node Node
280285function Clipboard :paste (node )
281- if self .data [ ACTION .cut ] [1 ] ~= nil then
282- self :do_paste (node , ACTION . cut , do_cut )
283- elseif self .data [ ACTION .copy ] [1 ] ~= nil then
284- self :do_paste (node , ACTION . copy , do_copy )
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 , " copy" , do_copy )
285290 end
286291end
287292
288293function Clipboard :print_clipboard ()
289294 local content = {}
290- if # self .data [ ACTION .cut ] > 0 then
295+ if # self .data .cut > 0 then
291296 table.insert (content , " Cut" )
292- for _ , node in pairs (self .data [ ACTION .cut ] ) do
297+ for _ , node in pairs (self .data .cut ) do
293298 table.insert (content , " * " .. (notify .render_path (node .absolute_path )))
294299 end
295300 end
296- if # self .data [ ACTION .copy ] > 0 then
301+ if # self .data .copy > 0 then
297302 table.insert (content , " Copy" )
298- for _ , node in pairs (self .data [ ACTION .copy ] ) do
303+ for _ , node in pairs (self .data .copy ) do
299304 table.insert (content , " * " .. (notify .render_path (node .absolute_path )))
300305 end
301306 end
@@ -305,65 +310,45 @@ end
305310
306311--- @param content string
307312function Clipboard :copy_to_reg (content )
308- local clipboard_name
309- local reg
310- if self .config .actions .use_system_clipboard == true then
311- clipboard_name = " system"
312- reg = " +"
313- else
314- clipboard_name = " neovim"
315- reg = " 1"
316- end
317-
318313 -- manually firing TextYankPost does not set vim.v.event
319314 -- workaround: create a scratch buffer with the clipboard contents and send a yank command
320315 local temp_buf = vim .api .nvim_create_buf (false , true )
321316 vim .api .nvim_buf_set_text (temp_buf , 0 , 0 , 0 , 0 , { content })
322317 vim .api .nvim_buf_call (temp_buf , function ()
323- vim .cmd (string.format (' normal! "%sy$' , reg ))
318+ vim .cmd (string.format (' normal! "%sy$' , self . reg ))
324319 end )
325320 vim .api .nvim_buf_delete (temp_buf , {})
326321
327- notify .info (string.format (" Copied %s to %s clipboard!" , content , clipboard_name ))
322+ notify .info (string.format (" Copied %s to %s clipboard!" , content , self . clipboard_name ))
328323end
329324
330325--- @param node Node
331326function Clipboard :copy_filename (node )
332- local content
333-
334327 if node .name == " .." then
335328 -- root
336- content = vim .fn .fnamemodify (self .explorer .absolute_path , " :t" )
329+ self : copy_to_reg ( vim .fn .fnamemodify (self .explorer .absolute_path , " :t" ) )
337330 else
338331 -- node
339- content = node .name
332+ self : copy_to_reg ( node .name )
340333 end
341-
342- self :copy_to_reg (content )
343334end
344335
345336--- @param node Node
346337function Clipboard :copy_basename (node )
347- local content
348-
349338 if node .name == " .." then
350339 -- root
351- content = vim .fn .fnamemodify (self .explorer .absolute_path , " :t:r" )
340+ self : copy_to_reg ( vim .fn .fnamemodify (self .explorer .absolute_path , " :t:r" ) )
352341 else
353342 -- node
354- content = vim .fn .fnamemodify (node .name , " :r" )
343+ self : copy_to_reg ( vim .fn .fnamemodify (node .name , " :r" ) )
355344 end
356-
357- self :copy_to_reg (content )
358345end
359346
360347--- @param node Node
361348function Clipboard :copy_path (node )
362- local content
363-
364349 if node .name == " .." then
365350 -- root
366- content = utils .path_add_trailing (" " )
351+ self : copy_to_reg ( utils .path_add_trailing (" " ) )
367352 else
368353 -- node
369354 local absolute_path = node .absolute_path
@@ -373,10 +358,12 @@ function Clipboard:copy_path(node)
373358 end
374359
375360 local relative_path = utils .path_relative (absolute_path , cwd )
376- content = node .nodes ~= nil and utils .path_add_trailing (relative_path ) or relative_path
361+ if node :is (DirectoryNode ) then
362+ self :copy_to_reg (utils .path_add_trailing (relative_path ))
363+ else
364+ self :copy_to_reg (relative_path )
365+ end
377366 end
378-
379- self :copy_to_reg (content )
380367end
381368
382369--- @param node Node
@@ -394,14 +381,14 @@ end
394381--- @param node Node
395382--- @return boolean
396383function Clipboard :is_cut (node )
397- return vim .tbl_contains (self .data [ ACTION .cut ] , node )
384+ return vim .tbl_contains (self .data .cut , node )
398385end
399386
400387--- Node is copied. Will not be cut.
401388--- @param node Node
402389--- @return boolean
403390function Clipboard :is_copied (node )
404- return vim .tbl_contains (self .data [ ACTION .copy ] , node )
391+ return vim .tbl_contains (self .data .copy , node )
405392end
406393
407394return Clipboard
0 commit comments