@@ -22,12 +22,12 @@ int os_get_uname(uv_uid_t uid, char *s, size_t len);
2222--- @field split string | table<string , string>
2323--- @field vsplit string | table<string , string>
2424--- @field switch string | table<string , string>
25- --- @field execute string | table<string , string>
2625
2726--- @class DiredConfig
2827--- @field shortcuts string
2928--- @field show_hidden boolean
3029--- @field normal_when_fits boolean
30+ --- @filed use_trash boolean
3131--- @field file_dir_based boolean
3232--- @field keymaps KeyMapConfig
3333
@@ -39,6 +39,7 @@ local Config = setmetatable({}, {
3939 normal_when_fits = true ,
4040 file_dir_based = true ,
4141 shortcuts = ' sdfhlwertyuopzxcvbnmSDFGHLQWERTYUOPZXCVBNM' ,
42+ use_trash = true ,
4243 keymaps = {
4344 open = { i = ' <CR>' , n = ' <CR>' }, -- both on search and main buffer
4445 up = { i = ' <C-u>' , n = ' <C-u>' }, -- both on search and main buffer
@@ -48,7 +49,6 @@ local Config = setmetatable({}, {
4849 split = { n = ' gs' , i = ' <C-s>' }, -- both on search and main buffer
4950 vsplit = { n = ' gv' , i = ' <C-v>' }, -- both on search and main buffer
5051 switch = { i = ' <C-j>' , n = ' <C-j>' }, -- both on search and main buffer
51- execute = ' <C-s>' , -- main buffer
5252 },
5353 }
5454 if vim .g .dired and vim .g .dired [scope ] ~= nil then
@@ -301,10 +301,11 @@ UI.Window = {
301301 vim .bo [buf ].bufhidden = ' wipe'
302302 vim .bo [buf ].textwidth = 2000
303303
304+ local height = math.min (math.floor (vim .o .lines * 0.5 ), 25 )
304305 local win = api .nvim_open_win (buf , false , {
305306 relative = ' editor' ,
306307 width = config .width ,
307- height = 25 , -- make sure less than length of shortcuts count
308+ height = height , -- make sure less than length of shortcuts count
308309 row = config .row ,
309310 col = config .col ,
310311 border = {
@@ -333,7 +334,9 @@ UI.Window = {
333334 end ,
334335 event = function (state )
335336 return F .IO .fromEffect (function ()
337+ state .group = api .nvim_create_augroup (' DiredGroup' , {})
336338 api .nvim_create_autocmd (' CursorMoved' , {
339+ group = state .group ,
337340 buffer = state .buf ,
338341 callback = function ()
339342 local row = api .nvim_win_get_cursor (state .win )[1 ] - 1
@@ -350,6 +353,14 @@ UI.Window = {
350353 end
351354 end ,
352355 })
356+
357+ api .nvim_create_autocmd ({ ' InsertLeave' }, {
358+ group = state .group ,
359+ buffer = state .buf ,
360+ callback = function ()
361+ Browser .applyChanges (state )
362+ end ,
363+ })
353364 return state
354365 end )
355366 end ,
@@ -367,10 +378,10 @@ UI.Window = {
367378 if current_buf ~= state .buf or api .nvim_get_current_win () ~= state .win then
368379 return
369380 end
370- local char = vim . fn . nr2char ( vim . fn . char2nr ( key ))
381+
371382 if mode == ' no' then
372383 -- copy
373- if char == ' Y' or (char == ' y' and state .vim_reg .last_key == ' y' ) then
384+ if key == ' Y' or (key == ' y' and state .vim_reg .last_key == ' y' ) then
374385 state .operation_mode = ' yank'
375386 local cursor_pos = api .nvim_win_get_cursor (state .win )
376387 local line_idx = cursor_pos [1 ]
@@ -388,50 +399,82 @@ UI.Window = {
388399 end
389400
390401 -- delete
391- if char == ' D ' or ( char == ' d' and state .vim_reg .last_key == ' d' ) then
402+ if key == ' d' and state .vim_reg .last_key == ' d' then
392403 state .operation_mode = ' delete'
393404 local cursor_pos = api .nvim_win_get_cursor (state .win )
394405 local line_idx = cursor_pos [1 ]
395406 if state .entries [line_idx ] then
396- state .clipboard = {
397- type = ' cut' ,
398- entries = { state .entries [line_idx ] },
399- source_path = state .current_path ,
400- }
401-
402- if api .nvim_get_current_line ():match (SEPARATOR .. ' $' ) then
403- Notify .info (' delete folder' )
407+ local text = api .nvim_get_current_line ():gsub (' %s+$' , ' ' )
408+ if vim .endswith (text , SEPARATOR ) then
409+ Notify .info (' delete folder ' .. state .entries [line_idx ].name )
404410 else
405- Notify .info (' cut one file' )
411+ Notify .info (' delete file ' .. state . entries [ line_idx ]. name )
406412 end
407413 end
408-
414+ vim .schedule (function ()
415+ Browser .applyChanges (state )
416+ end )
409417 state .operation_mode = nil
410418 end
411419 end
412420
413421 if mode == ' n' then
414- if char == ' p' then
422+ if key == ' p' then
415423 if state .clipboard and state .clipboard .entries and # state .clipboard .entries > 0 then
416424 Browser .executeClipboardOperation (state )
417425 else
418426 Notify .info (' clipboard is empty' )
419427 end
420428 end
421429
422- if char == ' v' or char == ' V' then
430+ if key == ' r' or key == ' R' then
431+ state .operation_mode = ' replace'
432+ state .operation_start_line = api .nvim_win_get_cursor (state .win )[1 ]
433+ end
434+
435+ if key == ' v' or key == ' V' then
423436 state .operation_mode = ' visual'
437+ state .operation_start_line = api .nvim_win_get_cursor (state .win )[1 ]
438+ end
439+
440+ -- cut
441+ if key == ' D' then
424442 local cursor_pos = api .nvim_win_get_cursor (state .win )
425- state .operation_start_line = cursor_pos [1 ]
443+ local line_idx = cursor_pos [1 ]
444+ if state .entries [line_idx ] then
445+ state .clipboard = {
446+ type = ' cut' ,
447+ entries = { state .entries [line_idx ] },
448+ source_path = state .current_path ,
449+ }
450+ vim .api .nvim_command (' normal! dd' )
451+ if api .nvim_get_current_line ():match (SEPARATOR .. ' $' ) then
452+ Notify .info (' cut folder ' .. state .entries [line_idx ].name )
453+ else
454+ Notify .info (' cut file ' .. state .entries [line_idx ].name )
455+ end
456+ return ' '
457+ end
426458 end
427459 end
428460
461+ if
462+ mode == ' R'
463+ and state .operation_mode == ' replace'
464+ and api .nvim_win_get_cursor (state .win )[1 ] == state .operation_start_line
465+ then
466+ vim .schedule (function ()
467+ Browser .applyChanges (state )
468+ end )
469+ return
470+ end
471+
429472 -- visual mode
430473 if mode == ' v' or mode == ' V' then
431474 local cursor_pos = api .nvim_win_get_cursor (state .win )
432475 state .operation_end_line = cursor_pos [1 ]
433476
434- if char == ' y' then
477+ if key == ' y' then
435478 local start_line = math.min (state .operation_start_line , state .operation_end_line )
436479 local end_line = math.max (state .operation_start_line , state .operation_end_line )
437480
@@ -455,7 +498,7 @@ UI.Window = {
455498 state .operation_mode = nil
456499 end
457500
458- if char == ' d' or char == ' D' then
501+ if key == ' d' or key == ' D' then
459502 local start_line = math.min (state .operation_start_line , state .operation_end_line )
460503 local end_line = math.max (state .operation_start_line , state .operation_end_line )
461504
@@ -479,7 +522,7 @@ UI.Window = {
479522 state .operation_mode = nil
480523 end
481524 end
482- state .vim_reg .last_key = char
525+ state .vim_reg .last_key = key
483526 end , ns_id , {})
484527
485528 return state
687730Browser .State = {
688731 create = function (path )
689732 local width = math.floor (vim .o .columns * 0.8 )
733+ local height = math.min (math.floor (vim .o .lines * 0.5 ), 25 )
690734 local dimensions = {
691735 width = width ,
692- row = math.floor ((vim .o .lines - 25 ) / 2 ),
736+ row = math.floor ((vim .o .lines - height ) / 2 ),
693737 col = math.floor ((vim .o .columns - width ) / 2 ),
694738 }
695739
@@ -715,6 +759,20 @@ Browser.State = {
715759 api .nvim_buf_set_lines (new_state .buf , 0 , - 1 , false , {})
716760 api .nvim_buf_clear_namespace (new_state .buf , ns_id , 0 , - 1 )
717761
762+ state .count_mark = api .nvim_buf_set_extmark (new_state .search_buf , ns_id , 0 , 0 , {
763+ id = state .count_mark or nil ,
764+ virt_text = {
765+ {
766+ (' [%d/%d] Find File: ' ):format (
767+ # entries_to_show > 0 and 1 or 0 ,
768+ # entries_to_show
769+ ),
770+ ' DiredTitle' ,
771+ },
772+ },
773+ virt_text_pos = ' inline' ,
774+ })
775+
718776 if # entries_to_show == 0 then
719777 return
720778 end
@@ -738,16 +796,6 @@ Browser.State = {
738796 api .nvim_feedkeys (api .nvim_replace_termcodes (' <ESC>' , true , false , true ), ' n' , true )
739797 end
740798
741- if api .nvim_buf_is_valid (new_state .search_buf ) then
742- state .count_mark = api .nvim_buf_set_extmark (new_state .search_buf , ns_id , 0 , 0 , {
743- id = state .count_mark or nil ,
744- virt_text = {
745- { (' [1/%s] Find File: ' ):format (# entries_to_show ), ' DiredTitle' },
746- },
747- virt_text_pos = ' inline' ,
748- })
749- end
750-
751799 if not s .initialized then
752800 local timer = assert (vim .uv .new_timer ())
753801 -- Attach buffer for search
@@ -1125,13 +1173,6 @@ Browser.setup = function(state)
11251173 end ,
11261174 buffer = { state .search_buf , state .buf },
11271175 },
1128- {
1129- key = Config .keymaps .execute ,
1130- action = function ()
1131- Browser .applyChanges (state )
1132- end ,
1133- buffer = state .buf ,
1134- },
11351176 }
11361177
11371178 local nmap = function (map )
@@ -1377,10 +1418,17 @@ Browser.executeOperations = function(state, operations)
13771418 local op = operations [index ]
13781419
13791420 if op .type == ' delete' then
1380- local task = op .is_directory and FileOps .deleteDirectory (op .path )
1381- or FileOps .deleteFile (op .path )
1421+ local task
1422+ if Config .use_trash then
1423+ task = FileOps .moveToTrash (op .path )
1424+ Notify .info (string.format (' Moving to trash: %s' , op .name ))
1425+ else
1426+ task = op .is_directory and FileOps .deleteDirectory (op .path ) or FileOps .deleteFile (op .path )
1427+ end
1428+
13821429 task .fork (function (err )
1383- table.insert (errors , ' Failed to delete ' .. op .name .. ' : ' .. err )
1430+ local action = Config .use_trash and ' move to trash' or ' delete'
1431+ table.insert (errors , string.format (' Failed to %s %s: %s' , action , op .name , err ))
13841432 vim .schedule (function ()
13851433 executeNextOperation (index + 1 )
13861434 end )
0 commit comments