How Superfile Handles File Copy Operations with Progress Tracking
Superfile implements file copy operations through a five-layer architecture that separates pure filesystem I/O from UI rendering, using a processbar.Process struct to track completion counts and charm.land/bubbles/v2/progress to render real-time percentage bars.
Superfile, a terminal file manager written in Go by yorukot/superfile, provides granular progress feedback during copy and move operations. The implementation delegates recursive file walking to pasteDir in src/internal/file_operations.go while maintaining thread-safe progress updates through a dedicated process bar model. Understanding how superfile handles file copy operations with progress tracking reveals a clean architectural pattern that balances performance with accurate visual feedback.
The Five-Layer Copy Architecture
Superfile's file copy implementation follows strict separation of concerns across five distinct layers. Each layer owns a specific responsibility, from raw disk I/O to terminal UI rendering.
Filesystem Logic Layer
The foundation resides in src/internal/file_operations.go, which contains pure I/O functions that never interact with the UI. Key functions include:
copyElement– Entry point that dispatches to file, directory, or symlink handlerscopyFile– Performs byte-stream copying between source and destinationcopyDir– Recursively creates directory structurescopyLinkFile– Handles symbolic link replication
These routines execute blocking filesystem calls and return only when the operation completes or fails.
Paste Orchestration Layer
The pasteDir function, also in file_operations.go, coordinates complex operations. It accepts two critical parameters for progress tracking:
func pasteDir(src, dst string, p *processbar.Process, cut bool, processBarModel *processbar.Model) error
This function determines whether a fast rename is possible (same-partition cut) or if a full copy-plus-delete cycle is required. While traversing the source tree, it invokes actualPasteOperation for each entry.
Per-File Operation Layer
The actualPasteOperation function bridges filesystem work and progress reporting. After successfully copying a file or creating a directory, it updates the process state:
p.CurrentFile = fileName
p.Done++
processBarModel.TrySendingUpdateProcessMsg(*p)
This ensures the UI receives updates atomically after each file completes, preventing progress bar jitter or loss of synchronization.
Progress Bar UI Layer
The visual feedback system operates through src/internal/ui/processbar/model.go and src/internal/ui/processbar/process.go. The Process struct tracks:
Total– Total number of files to processDone– Number of completed operationsCurrentFile– Name of the file currently being processedState– Operating, Finished, or Error
The processbar.Model calculates the percentage:
progressPercentage := float64(p.Done) / float64(p.Total)
It then renders the bar using the progress component from charm.land/bubbles/v2/progress, producing output like:
copy-operation ┃ ███████░░░ 57% (file.txt)
High-Level Command Handling
User commands enter through src/internal/handle_file_operations.go. The copySingleItem and copyMultipleItem functions:
- Validate source items via
PruneInaccessibleItemsAndGet() - Count total files using
getTotalFilesCnt(copyItems) - Initialize a
processbar.Processwith a UUID and total count - Invoke
executePasteOperation, which ultimately callspasteDir
Step-by-Step Progress Tracking Workflow
When you execute a copy command, the following sequence ensures accurate progress reporting:
- Initialization –
copySingleItemcreates aProcesswithTotal = getTotalFilesCnt(copyItems)and registers it withprocessbar.Model - Traversal –
pasteDirwalks the source directory tree, skipping inaccessible items - Execution – For each entry,
actualPasteOperationperforms the filesystem operation - Update – Post-operation, it increments
p.Done, setsp.CurrentFile, and callsTrySendingUpdateProcessMsg - Rendering – The UI thread calls
Model.Render, recalculating the percentage and redrawing the terminal bar - Completion – Upon finishing,
Process.Statetransitions toFinishedand the entry cleans up
Practical Code Examples
Copying a Single File
Copy a file to the current panel's destination:
spf cp src.txt
Under the hood, copySingleItem(false) creates a processbar.Process with Total = 1. The progress bar flashes briefly to 100% as pasteDir completes the single actualPasteOperation call.
Copying an Entire Directory
Recursively copy a folder to a target path:
spf cp myfolder/ /tmp/target/
The Go implementation handles this recursively:
func (m *model) copyMultipleItem(cut bool) {
copyItems := m.clipboard.PruneInaccessibleItemsAndGet()
reqID := uuid.New().String()
// Total is set to the recursive file count
m.executePasteOperation(&m.processBarModel, "/tmp/target/", copyItems, cut, reqID)
}
During execution, the UI displays incremental updates:
copy-operation ┃ ████░░░░░░ 30% (file1.txt)
Cross-Partition Move Operations
Move data across different filesystems:
spf cut myfolder/ /mnt/otherdisk/
When source and destination reside on different partitions, pasteDir detects that a fast rename is impossible and falls back to copy-then-delete. The progress bar tracks only the copy phase; deletion of the source tree occurs after the bar reaches 100%, ensuring you never see incomplete data in the destination.
Key Source Files
| File | Purpose | Key Components |
|---|---|---|
src/internal/file_operations.go |
Core copy logic and orchestration | pasteDir, actualPasteOperation, copyFile |
src/internal/ui/processbar/process.go |
Progress state definition | Process struct (Total, Done, CurrentFile) |
src/internal/ui/processbar/model.go |
UI rendering and process management | Model, TrySendingUpdateProcessMsg, rendering logic |
src/internal/handle_file_operations.go |
Command entry points | copySingleItem, copyMultipleItem, executePasteOperation |
src/internal/trash/trash_windows.go |
Windows-native progress sink | IFileOperationProgressSink COM implementation |
Summary
- Superfile separates filesystem I/O from UI rendering through a five-layer architecture implemented in
yorukot/superfile. pasteDirinfile_operations.goorchestrates recursive copying while accepting*processbar.Processfor state updates.actualPasteOperationupdatesProcess.DoneandCurrentFileafter each file, triggeringTrySendingUpdateProcessMsg.- Progress percentage is calculated as
float64(Done)/float64(Total)and rendered viacharm.land/bubbles/v2/progress. - Cross-partition moves fall back to copy-then-delete, with progress tracking covering only the copy phase.
Frequently Asked Questions
How does superfile calculate the percentage for copy progress?
Superfile calculates the percentage in processbar.Model using the ratio of completed versus total files: float64(p.Done)/float64(p.Total). The Process struct tracks Total (set during initialization by getTotalFilesCnt) and Done (incremented by actualPasteOperation after each successful file operation). This ratio drives the bubbles/v2/progress component to render the visual bar.
Why doesn't the progress bar appear to move smoothly during large file copies?
The progress bar updates per file, not per byte. If you copy a directory containing one small file and one multi-gigabyte file, the bar jumps to 50% after the small file completes, then stalls until the large file finishes. This is by design in actualPasteOperation, which calls TrySendingUpdateProcessMsg only after os.Copy or directory creation returns.
What happens when cutting and pasting across different filesystems?
When pasteDir detects that the source and destination are on different partitions (where os.Rename would fail with an EXDEV error), it executes a fallback path: it copies the entire tree using copyElement, updates the progress bar to 100%, and only then deletes the source files. This ensures data integrity—if the copy fails, the source remains intact.
Does superfile use native Windows progress dialogs?
On Windows, superfile optionally leverages the COM interface IFileOperationProgressSink defined in src/internal/trash/trash_windows.go for operations involving the system trash. However, standard copy operations between directories use the same Go-based processbar implementation as Linux and macOS, ensuring consistent terminal-based progress reporting across all platforms.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →