How Superfile's Selection Mode Works for Batch File Operations
Superfile's selection mode uses a map-based state tracker with an incrementing order counter to enable deterministic multi-file selection for batch copy, move, and delete operations.
Superfile, the terminal-based file manager by yorukot, implements a robust selection mode that transforms single-item navigation into powerful batch file operations. Understanding this mechanism reveals how the tool maintains selection order while providing visual feedback for bulk actions.
Selection State Architecture
The selection system resides in src/internal/ui/filepanel/utils.go and centers on two core properties within the filepanel model:
selected: Amap[string]intstoring absolute file paths as keys and incrementing integers representing selection order as valuesselectOrderCounter: An integer that increments with each new selection to establish deterministic "first-selected" semantics
This design allows Superfile to track not just what is selected, but when it was selected.
Core Selection Functions
Adding selections uses SetSelected, which increments the counter and records the location:
func (m *Model) SetSelected(location string) {
m.selectOrderCounter++
m.selected[location] = m.selectOrderCounter
}
Removing selections uses SetUnSelected with existence checking:
func (m * Model) SetUnSelected(location string) {
if m.CheckSelected(location) {
delete(m.selected, location)
}
}
Toggle behavior is handled by ToggleSelected, which calls either SetUnSelected or SetSelected depending on current state.
Selection Queries
The model provides several accessors for batch operations:
SelectedCount(): Returns the total number of selected itemsGetSelectedLocations(): Returns an unordered slice of pathsGetFirstSelectedLocation(): Walks the map to find the entry with the smallest order value (the initial selection)GetSelectedLocationsSortedAsVisible(): Returns paths ordered according to their visual position in the panel
Entering Selection Mode
Users activate selection mode through key bindings defined in the UI layer. When active, pressing Space invokes SingleItemSelect at src/internal/ui/filepanel/utils.go lines 117-122:
func (m *Model) SingleItemSelect() {
if !m.EmptyOrInvalid() {
m.ToggleSelected(m.GetFocusedItem().Location)
}
}
This toggles the current cursor location in the selected map. The mode state itself is managed by the surrounding Panel struct, which determines whether navigation commands affect the cursor position only or also update the selection set.
Executing Batch File Operations
When users trigger batch commands (copy, move, delete), the handler retrieves selections using GetSelectedLocationsSortedAsVisible. This ensures operations process files in visual order—critical for hierarchical moves or ordered processing:
selected := panel.GetSelectedLocationsSortedAsVisible()
if len(selected) == 0 {
// Fallback: operate on the focused item only
selected = []string{panel.GetFocusedItem().Location}
}
The operation iterates over this slice, performing filesystem actions on each path. Because GetSelectedLocationsSortedAsVisible walks the visible element list (m.element) and filters for selected items, the order matches exactly what the user sees on screen.
Practical Implementation Example
To implement a batch move operation using Superfile's selection API:
func batchMove(panel *filepanel.Model, dest string) error {
srcs := panel.GetSelectedLocationsSortedAsVisible()
if len(srcs) == 0 {
// No explicit selection → operate on the focused item
srcs = []string{panel.GetFocusedItem().Location}
}
for _, src := range srcs {
if err := fs.Move(src, filepath.Join(dest, filepath.Base(src))); err != nil {
return err
}
}
panel.ResetSelected() // Clear selections post-operation
return nil
}
Resetting and Clearing Selections
After completing batch operations or when reinitializing panels, ResetSelected clears the state:
func (m *Model) ResetSelected() {
m.selectOrderCounter = 0
m.selected = make(map[string]int)
}
This function appears at src/internal/ui/filepanel/utils.go lines 28-31 and ensures deterministic behavior by zeroing the counter and reinitializing the map.
The test suite in src/internal/ui/filepanel/selection_test.go (lines 9-55) validates this lifecycle, covering add, remove, multi-select, and reset operations.
Summary
- Superfile tracks selections using a
map[string]intwhere keys are absolute paths and values are incrementing order integers SetSelectedandToggleSelectedinsrc/internal/ui/filepanel/utils.gomanage the selection state with automatic orderingSingleItemSelectconnects the Space key to toggle the current cursor location in the selection setGetSelectedLocationsSortedAsVisibleensures batch operations process files in visual order as displayed to the userResetSelectedclears the map and counter after operations complete or when panels refresh
Frequently Asked Questions
How does Superfile remember which file was selected first?
Superfile uses the selectOrderCounter integer that increments each time SetSelected adds a new item. The GetFirstSelectedLocation function walks the selected map to find the entry with the smallest order value, providing deterministic access to the initial selection regardless of map iteration order.
What happens if I run a batch operation without selecting any files?
The command handler checks len(selected) and falls back to the currently focused item. If GetSelectedLocationsSortedAsVisible returns an empty slice, the code uses panel.GetFocusedItem().Location as the sole target, ensuring operations always have valid targets.
Why does Superfile sort selected locations by visible order rather than selection order?
While the selected map tracks selection order via integers, GetSelectedLocationsSortedAsVisible returns paths ordered by their position in the visible file list. This design ensures that batch operations like move or copy progress through the directory in the same sequence the user sees, preventing confusion when operating on hierarchies or large directories.
Where are selection mode tests located in the Superfile repository?
The selection lifecycle tests reside in src/internal/ui/filepanel/selection_test.go, covering the complete functionality from SetSelected through ResetSelected. These tests verify that the order counter increments correctly, toggles remove entries properly, and bulk selections work as expected.
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 →