@@ -12,14 +12,14 @@ import (
1212 "time"
1313
1414 variable "github.com/yorukot/superfile/src/config"
15+ "github.com/yorukot/superfile/src/internal/ui/notify"
1516 "github.com/yorukot/superfile/src/internal/ui/processbar"
1617 "github.com/yorukot/superfile/src/internal/utils"
1718
1819 "github.com/yorukot/superfile/src/internal/common"
1920
2021 "github.com/atotto/clipboard"
2122 tea "github.com/charmbracelet/bubbletea"
22- "github.com/lithammer/shortuuid"
2323 "github.com/yorukot/superfile/src/config/icon"
2424)
2525
@@ -57,20 +57,18 @@ func (m *model) IsRenamingConflicting() bool {
5757}
5858
5959// TODO: Remove channel messaging and use tea.Cmd
60- func (m * model ) warnModalForRenaming () {
61- id := shortuuid .New ()
62- message := channelMessage {
63- messageID : id ,
64- messageType : sendWarnModal ,
65- }
66-
67- message .warnModal = warnModal {
68- open : true ,
69- title : "There is already a file or directory with that name" ,
70- content : "This operation will override the existing file" ,
71- warnType : confirmRenameItem ,
72- }
73- channel <- message
60+ func (m * model ) warnModalForRenaming () tea.Cmd {
61+ reqID := m .ioReqCnt
62+ m .ioReqCnt ++
63+ slog .Debug ("Submitting rename notify model request" , "reqID" , reqID )
64+ res := func () tea.Msg {
65+ notifyModel := notify .New (true ,
66+ common .SameRenameWarnTitle ,
67+ common .SameRenameWarnContent ,
68+ notify .RenameAction )
69+ return NewNotifyModalMsg (notifyModel , reqID )
70+ }
71+ return res
7472}
7573
7674// Rename file where the cusror is located
@@ -156,37 +154,26 @@ func deleteOperation(processBarModel *processbar.Model, items []string, useTrash
156154 return p .State
157155}
158156
159- func (m * model ) deleteItemWarn () {
160- panel := & m .fileModel .filePanels [m .filePanelFocusIndex ]
161-
157+ func (m * model ) getDeleteTriggerCmd () tea.Cmd {
158+ panel := m .getFocusedFilePanel ()
162159 if (panel .panelMode == selectMode && len (panel .selected ) == 0 ) ||
163160 (panel .panelMode == browserMode && len (panel .element ) == 0 ) {
164- return
161+ return nil
165162 }
166163
167- id := shortuuid .New ()
168- message := channelMessage {
169- messageID : id ,
170- messageType : sendWarnModal ,
171- }
164+ reqID := m .ioReqCnt
165+ m .ioReqCnt ++
172166
173- if ! hasTrash || isExternalDiskPath (panel .location ) {
174- message .warnModal = warnModal {
175- open : true ,
176- title : "Are you sure you want to completely delete" ,
177- content : "This operation cannot be undone and your data will be completely lost." ,
178- warnType : confirmDeleteItem ,
167+ return func () tea.Msg {
168+ title := "Are you sure you want to move this to trash can"
169+ content := "This operation will move file or directory to trash can."
170+
171+ if ! hasTrash || isExternalDiskPath (panel .location ) {
172+ title = "Are you sure you want to completely delete"
173+ content = "This operation cannot be undone and your data will be completely lost."
179174 }
180- channel <- message
181- return
175+ return NewNotifyModalMsg (notify .New (true , title , content , notify .DeleteAction ), reqID )
182176 }
183- message .warnModal = warnModal {
184- open : true ,
185- title : "Are you sure you want to move this to trash can" ,
186- content : "This operation will move file or directory to trash can." ,
187- warnType : confirmDeleteItem ,
188- }
189- channel <- message
190177}
191178
192179// Copy directory or file's path to superfile's clipboard
@@ -229,86 +216,49 @@ func (m *model) getPasteItemCmd() tea.Cmd {
229216
230217 slog .Debug ("Submitting pasteItems request" , "id" , reqID , "items cnt" , len (copyItems ), "dest" , panelLocation )
231218 return func () tea.Msg {
219+ err := validatePasteOperation (panelLocation , copyItems , cut )
220+ if err != nil {
221+ return NewNotifyModalMsg (notify .New (true , "Invalid paste location" , err .Error (), notify .NoAction ),
222+ reqID )
223+ }
232224 state := executePasteOperation (& m .processBarModel , panelLocation , copyItems , cut )
233225 return NewPasteOperationMsg (state , reqID )
234226 }
235227}
236228
237- // Paste all clipboard items
238- func executePasteOperation (processBarModel * processbar.Model ,
239- panelLocation string , copyItems []string , cut bool ) processbar.ProcessState {
240- if len (copyItems ) == 0 {
241- return processbar .Cancelled
242- }
243-
244- id := shortuuid .New ()
245-
229+ func validatePasteOperation (panelLocation string , copyItems []string , cut bool ) error {
246230 // Check if trying to paste into source or subdirectory for both cut and copy operations
247231 for _ , srcPath := range copyItems {
248232 // Check if trying to cut and paste into the same directory - this would be a no-op
249233 // and could potentially cause issues, so we prevent it
250234 if filepath .Dir (srcPath ) == panelLocation && cut {
251- slog .Error ("Cannot paste into parent directory of source" , "src" , srcPath , "dst" , panelLocation )
252- message := channelMessage {
253- messageID : id ,
254- messageType : sendNotifyModal ,
255- notifyModal : notifyModal {
256- open : true ,
257- title : "Invalid paste location" ,
258- content : "Cannot paste into parent directory of source" ,
259- },
260- }
261- channel <- message
262- return processbar .Cancelled
235+ return fmt .Errorf ("cannot paste into parent directory of source, srcPath : %v, panelLocation : %v" ,
236+ srcPath , panelLocation )
263237 }
264-
265- slog .Debug ("model.pasteItem" , "srcPath" , srcPath , "panel location" , panelLocation )
266-
267238 if cut && srcPath == panelLocation {
268- slog .Error ("Cannot paste a directory into itself" , "operation" , "cut" , "src" , srcPath , "dst" , panelLocation )
269- message := channelMessage {
270- messageID : id ,
271- messageType : sendNotifyModal ,
272- notifyModal : notifyModal {
273- open : true ,
274- title : "Invalid paste location" ,
275- content : "Cannot paste a directory into itself" ,
276- },
277- }
278- channel <- message
279- return processbar .Cancelled
239+ return errors .New ("cannot paste a directory into itself" )
280240 }
281241
282242 if isAncestor (srcPath , panelLocation ) {
283- operation := "copy"
284- if cut {
285- operation = "cut"
286- }
287-
288- slog .Error ("Cannot paste a directory into itself or its subdirectory" ,
289- "operation" , operation , "src" , srcPath , "dst" , panelLocation )
290- message := channelMessage {
291- messageID : id ,
292- messageType : sendNotifyModal ,
293- notifyModal : notifyModal {
294- open : true ,
295- title : "Invalid paste location" ,
296- content : fmt .Sprintf ("Cannot %s and paste a directory into itself or its subdirectory" , operation ),
297- },
298- }
299- channel <- message
300- return processbar .Cancelled
243+ return fmt .Errorf ("cannot %s and paste a directory into itself or its subdirectory" ,
244+ getCopyOrCutOperationName (cut ))
301245 }
302246 }
303247
304- slog .Debug ("model.pasteItem" , "items" , copyItems , "cut" , cut , "panel location" , panelLocation )
248+ return nil
249+ }
305250
306- prefixIcon := icon .Copy + icon .Space
307- if cut {
308- prefixIcon = icon .Cut + icon .Space
309- }
251+ // new func to check and return an error that will go in m.content
252+ // create a new error type
310253
311- p , err := processBarModel .SendAddProcessMsg (prefixIcon + filepath .Base (copyItems [0 ]), len (copyItems ), true )
254+ // Paste all clipboard items
255+ func executePasteOperation (processBarModel * processbar.Model ,
256+ panelLocation string , copyItems []string , cut bool ) processbar.ProcessState {
257+ slog .Debug ("executePasteOperation" , "items" , copyItems , "cut" , cut , "panel location" , panelLocation )
258+
259+ p , err := processBarModel .SendAddProcessMsg (
260+ icon .GetCopyOrCutIcon (cut )+ icon .Space + filepath .Base (copyItems [0 ]),
261+ getTotalFilesCnt (copyItems ), true )
312262 if err != nil {
313263 slog .Error ("Cannot spawn a new process" , "error" , err )
314264 return processbar .Failed
@@ -330,25 +280,20 @@ func executePasteOperation(processBarModel *processbar.Model,
330280 }
331281 }
332282
333- prefixIcon := icon .Copy
334- if cut {
335- prefixIcon = icon .Cut
336- }
337- p .Name = prefixIcon + icon .Space + filepath .Base (filePath )
283+ p .Name = icon .GetCopyOrCutIcon (cut ) + icon .Space + filepath .Base (filePath )
338284 if err != nil {
339285 slog .Debug ("model.pasteItem - paste failure" , "error" , err ,
340286 "current item" , filePath , "errMessage" , errMessage )
341287 p .State = processbar .Failed
342288 slog .Error (errMessage , "error" , err )
343289 break
344290 }
345-
346- p .Done ++
347291 processBarModel .TrySendingUpdateProcessMsg (p )
348292 }
349293
350294 if p .State != processbar .Failed {
351295 p .State = processbar .Successful
296+ p .Done = p .Total
352297 }
353298 p .DoneTime = time .Now ()
354299 err = processBarModel .SendUpdateProcessMsg (p , true )
@@ -359,6 +304,31 @@ func executePasteOperation(processBarModel *processbar.Model,
359304 return p .State
360305}
361306
307+ func getTotalFilesCnt (copyItems []string ) int {
308+ totalFiles := 0
309+ for _ , folderPath := range copyItems {
310+ // TODO : Fix this. This is inefficient
311+ // In case of a cut operations for a directory with a lot of files
312+ // we are unnecessarily walking the whole directory recursively
313+ // while os will just perform a rename
314+ // So instead of few operations this will cause the cut paste
315+ // to read the whole directory recursively
316+ // we should avoid doing this.
317+ // Although this allows us a more detailed progress tracking
318+ // this make the copy/cut more inefficient
319+ // instead, we could just track progress based on total items in
320+ // copyItems
321+ // efficiency should be prioritized over more detailed feedback.
322+ count , err := countFiles (folderPath )
323+ if err != nil {
324+ slog .Error ("Error in countFiles" , "error" , err )
325+ continue
326+ }
327+ totalFiles += count
328+ }
329+ return totalFiles
330+ }
331+
362332// Extract compressed file
363333// TODO : err should be returned and properly handled by the caller
364334func (m * model ) getExtractFileCmd () tea.Cmd {
0 commit comments