# How Superfile Handles File Copy Operations with Progress Tracking

> Discover how Superfile's five-layer architecture manages file copy operations with progress tracking using processbar Process and charm land bubbles for real-time percentage updates.

- Repository: [Yorukot/superfile](https://github.com/yorukot/superfile)
- Tags: internals
- Published: 2026-07-26

---

**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`](https://github.com/yorukot/superfile/blob/main/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`](https://github.com/yorukot/superfile/blob/main/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 handlers
- `copyFile` – Performs byte-stream copying between source and destination
- `copyDir` – Recursively creates directory structures
- `copyLinkFile` – 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`](https://github.com/yorukot/superfile/blob/main/file_operations.go), coordinates complex operations. It accepts two critical parameters for progress tracking:

```go
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:

```go
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`](https://github.com/yorukot/superfile/blob/main/src/internal/ui/processbar/model.go) and [`src/internal/ui/processbar/process.go`](https://github.com/yorukot/superfile/blob/main/src/internal/ui/processbar/process.go). The `Process` struct tracks:

- `Total` – Total number of files to process
- `Done` – Number of completed operations
- `CurrentFile` – Name of the file currently being processed
- `State` – Operating, Finished, or Error

The `processbar.Model` calculates the percentage:

```go
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`](https://github.com/yorukot/superfile/blob/main/src/internal/handle_file_operations.go). The `copySingleItem` and `copyMultipleItem` functions:

1. Validate source items via `PruneInaccessibleItemsAndGet()`
2. Count total files using `getTotalFilesCnt(copyItems)`
3. Initialize a `processbar.Process` with a UUID and total count
4. Invoke `executePasteOperation`, which ultimately calls `pasteDir`

## Step-by-Step Progress Tracking Workflow

When you execute a copy command, the following sequence ensures accurate progress reporting:

1. **Initialization** – `copySingleItem` creates a `Process` with `Total = getTotalFilesCnt(copyItems)` and registers it with `processbar.Model`
2. **Traversal** – `pasteDir` walks the source directory tree, skipping inaccessible items
3. **Execution** – For each entry, `actualPasteOperation` performs the filesystem operation
4. **Update** – Post-operation, it increments `p.Done`, sets `p.CurrentFile`, and calls `TrySendingUpdateProcessMsg`
5. **Rendering** – The UI thread calls `Model.Render`, recalculating the percentage and redrawing the terminal bar
6. **Completion** – Upon finishing, `Process.State` transitions to `Finished` and the entry cleans up

## Practical Code Examples

### Copying a Single File

Copy a file to the current panel's destination:

```bash
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:

```bash
spf cp myfolder/ /tmp/target/

```

The Go implementation handles this recursively:

```go
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:

```bash
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`](https://github.com/yorukot/superfile/blob/main/src/internal/file_operations.go) | Core copy logic and orchestration | `pasteDir`, `actualPasteOperation`, `copyFile` |
| [`src/internal/ui/processbar/process.go`](https://github.com/yorukot/superfile/blob/main/src/internal/ui/processbar/process.go) | Progress state definition | `Process` struct (Total, Done, CurrentFile) |
| [`src/internal/ui/processbar/model.go`](https://github.com/yorukot/superfile/blob/main/src/internal/ui/processbar/model.go) | UI rendering and process management | `Model`, `TrySendingUpdateProcessMsg`, rendering logic |
| [`src/internal/handle_file_operations.go`](https://github.com/yorukot/superfile/blob/main/src/internal/handle_file_operations.go) | Command entry points | `copySingleItem`, `copyMultipleItem`, `executePasteOperation` |
| [`src/internal/trash/trash_windows.go`](https://github.com/yorukot/superfile/blob/main/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`.
- **`pasteDir`** in [`file_operations.go`](https://github.com/yorukot/superfile/blob/main/file_operations.go) orchestrates recursive copying while accepting `*processbar.Process` for state updates.
- **`actualPasteOperation`** updates `Process.Done` and `CurrentFile` after each file, triggering `TrySendingUpdateProcessMsg`.
- **Progress percentage** is calculated as `float64(Done)/float64(Total)` and rendered via `charm.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`](https://github.com/yorukot/superfile/blob/main/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.