# How superfile Implements File Operations (Copy, Paste, Cut, Delete): A Deep Dive into the Go Source Code

> Explore how superfile handles file operations like copy, paste, cut, and delete. Dive into the Go source code to understand its model-centric workflow, clipboard management, and TUI integration.

- Repository: [Yorukot/superfile](https://github.com/yorukot/superfile)
- Tags: deep-dive
- Published: 2026-07-28

---

**Superfile implements file operations through a model-centric workflow that combines clipboard management, process bar progress tracking, and low-level filesystem utilities to handle copy, paste, cut, and delete actions across the TUI.**

The open-source terminal file manager [superfile](https://github.com/yorukot/superfile) (by yorukot/superfile) orchestrates file operations through a sophisticated three-layer architecture. This design separates UI interactions from filesystem execution, enabling progress tracking and safe error handling while supporting advanced features like cross-partition moves and trash integration. Understanding this implementation reveals how modern Go-based TUI applications manage complex I/O operations without blocking the interface.

## The Three-Layer Architecture of superfile File Operations

The implementation divides responsibilities across distinct layers that communicate through Bubble Tea commands (`tea.Cmd`) and message passing.

| Layer | Responsibility | Key Files |
|-------|----------------|-----------|
| **UI → Model** | Translates hotkeys into model methods that manipulate the clipboard and create commands | [`src/internal/handle_file_operations.go`](https://github.com/yorukot/superfile/blob/main/src/internal/handle_file_operations.go) |
| **Model → Processor** | Creates process bar entries and delegates work to background processors | [`src/internal/handle_file_operations.go`](https://github.com/yorukot/superfile/blob/main/src/internal/handle_file_operations.go) |
| **Processor → Utils** | Executes actual filesystem calls with partition awareness and error handling | [`src/internal/file_operations.go`](https://github.com/yorukot/superfile/blob/main/src/internal/file_operations.go) |

This separation allows superfile to display real-time progress bars while safely handling symlinks, duplicate names, and permission errors in the background.

## Copy and Cut Operations

### Clipboard Management in the Model

Superfile maintains an internal clipboard structure (`m.clipboard`) that stores absolute paths alongside a boolean flag indicating whether the operation is a **cut** (move) or **copy**. When a user triggers a copy or cut action, the model resets the clipboard and populates it with the selected items.

In [`src/internal/handle_file_operations.go`](https://github.com/yorukot/superfile/blob/main/src/internal/handle_file_operations.go), the `copySingleItem` method handles individual file operations:

```go
func (m *model) copySingleItem(cut bool) {
    panel := m.getFocusedFilePanel()
    m.clipboard.Reset(cut)                     // Reset and set cut flag
    if panel.Empty() { return }
    m.clipboard.Add(panel.GetFocusedItem().Location)
}

```

The `cut` parameter determines the later behavior during paste operations—`true` triggers a move, while `false` triggers a copy.

### Single vs Multiple Item Selection

For batch operations, `copyMultipleItem` iterates over selected entries and stores them sorted by visible order:

```go
func (m *model) copyMultipleItem(cut bool) {
    panel := m.getFocusedFilePanel()
    m.clipboard.Reset(cut)
    if panel.SelectedCount() == 0 { return }
    items := panel.GetSelectedLocationsSortedAsVisible()
    m.clipboard.SetItems(items)
}

```

Both methods ensure the clipboard is primed before any paste command executes, with the cut flag preserved for the subsequent operation.

## Paste Operations and Validation

### Validating Paste Destinations

When the user initiates a paste, `getPasteItemCmd` validates the operation before creating the background processor. This prevents dangerous operations like moving a directory into itself or its subdirectories.

The validation logic in [`src/internal/handle_file_operations.go`](https://github.com/yorukot/superfile/blob/main/src/internal/handle_file_operations.go) uses `isAncestor` to detect circular references:

```go
func (m *model) getPasteItemCmd() tea.Cmd {
    copyItems := m.clipboard.PruneInaccessibleItemsAndGet()
    cut := m.clipboard.IsCut()
    if len(copyItems) == 0 { return nil }
    reqID := m.nextIoReqCnt()
    panelLocation := m.getFocusedFilePanel().Location
    return func() tea.Msg {
        if err := validatePasteOperation(panelLocation, copyItems, cut); err != nil {
            return NewNotifyModalMsg(notify.New(true, "Invalid paste location", err.Error(), notify.NoAction), reqID)
        }
        return m.executePasteOperation(&m.processBarModel, panelLocation, copyItems, cut, reqID)
    }
}

```

### The Paste Processor Workflow

The `executePasteOperation` function creates a `processbar.Process` entry and selects the appropriate operation type (`processbar.OpCopy` or `processbar.OpCut`). It then delegates to `makePasteProcessor`, which iterates over source paths and chooses the optimal transfer method:

- **`moveElement`** – Used for cuts where source and destination reside on the same partition (fast rename)
- **`pasteDir`** – Handles cross-partition moves and all copy operations via recursive file walking

This optimization avoids unnecessary data duplication when a simple rename suffices.

## Delete Operations and Trash Handling

Deletion follows a similar processor pattern. The `getDeleteCmd` method gathers selected items and determines whether to use the system trash or permanent deletion based on user configuration.

The processor created by `makeDeleteProcessor` iterates over the target list and calls:
- **`trash.Move`** – For safe deletion (moves to recycle bin)
- **`os.RemoveAll`** – For permanent deletion when trash is disabled or unavailable

Errors abort the operation and propagate back to the UI through the process bar system, ensuring users receive immediate feedback on permission failures or locked files.

## Low-Level Filesystem Utilities

The core logic resides in [`src/internal/file_operations.go`](https://github.com/yorukot/superfile/blob/main/src/internal/file_operations.go), which provides partition-aware utilities that handle edge cases like symlinks and duplicate filenames.

### moveElement and Partition Optimization

`moveElement` checks whether source and destination exist on the same partition using `isSamePartition`. If they match, it attempts a fast rename; if the rename fails or partitions differ, it falls back to copy-then-delete:

```go
func moveElement(src, dst string) error {
    // Check same partition for optimization
    if isSamePartition(src, dst) {
        return os.Rename(src, dst)
    }
    // Fallback to copy-then-delete for cross-partition moves
    if err := copyElement(src, dst); err != nil {
        return err
    }
    return os.RemoveAll(src)
}

```

### copyElement and Recursive Directory Handling

`copyElement` dispatches to type-specific handlers:
- **`copyDir`** – Recursively creates destination directories while preserving mode bits, iterating through entries and calling `copyElement` for nested items
- **`copyFile`** – Streams data via `io.Copy` between source and destination file handles

For complex paste operations, `pasteDir` coordinates the recursive walk and delegates single-file operations to `actualPasteOperation`, which updates the process bar state after each file transfer.

### Safety Checks with isAncestor

The `isAncestor` function provides critical protection against filesystem corruption by resolving symlinks and checking if the destination path is contained within the source path. This prevents users from accidentally moving a parent directory into its own child, which would destroy data.

## Progress Tracking with the Process Bar

All file operations integrate with superfile's process bar system (`processbar.Model`) to provide visual feedback:

1. **Initialization** – `processBarModel.SendAddProcessMsg` creates a UI entry with the total item count and operation name
2. **Progress Updates** – The processor updates `process.CurrentFile` and `process.Done` fields, pushing changes via `TrySendingUpdateProcessMsg`
3. **Completion** – `markProcessDone` records the final status and timestamp, updating the UI with success or failure indicators

This architecture ensures the TUI remains responsive even during large file transfers, as the heavy I/O runs in background goroutines while the main thread handles rendering.

## Summary

- **superfile** implements file operations through a three-layer architecture separating UI commands, clipboard management, and filesystem execution.
- The **clipboard** stores paths and a cut flag in [`handle_file_operations.go`](https://github.com/yorukot/superfile/blob/main/handle_file_operations.go), determining whether subsequent pastes perform moves or copies.
- **Validation** via `isAncestor` and `validatePasteOperation` prevents dangerous operations like moving directories into themselves.
- **Partition awareness** in `moveElement` optimizes same-device moves using fast renames instead of copy-then-delete.
- **Process bar integration** provides real-time progress tracking for all I/O operations through background processors that report to the UI model.

## Frequently Asked Questions

### How does superfile handle cut operations differently from copy operations?

Superfile stores a boolean `cut` flag in the clipboard when users trigger `copySingleItem(true)` or `copyMultipleItem(true)`. During paste execution, this flag determines whether the processor calls `moveElement` (for cuts) or `pasteDir` (for copies). For cuts on the same partition, superfile attempts a fast rename via `os.Rename` rather than duplicating data.

### What prevents users from accidentally moving a folder into its own subdirectory?

The `validatePasteOperation` function in [`src/internal/handle_file_operations.go`](https://github.com/yorukot/superfile/blob/main/src/internal/handle_file_operations.go) calls `isAncestor` to check if the destination path is equal to or contained within any source path. This includes symlink resolution, ensuring the operation aborts before any filesystem changes occur if a circular reference is detected.

### Does superfile support trash/recycle bin functionality?

Yes. When the `getDeleteCmd` receives a `false` parameter (indicating non-permanent deletion), the delete processor calls `trash.Move` from platform-specific wrappers in `src/internal/trash/`. This moves files to the OS recycle bin instead of permanently deleting them. If trash functionality is unavailable, it falls back to `os.RemoveAll`.

### How does superfile optimize file moves across different partitions?

The `moveElement` function in [`src/internal/file_operations.go`](https://github.com/yorukot/superfile/blob/main/src/internal/file_operations.go) first checks `isSamePartition` to compare device IDs. If source and destination share the same partition, it uses `os.Rename` for an instantaneous metadata update. For cross-partition moves, it falls back to `copyElement` followed by `os.RemoveAll`, ensuring data integrity while optimizing for the fast path when possible.