# How Superfile's Prompt Command Line Mode Executes Shell Commands

> Discover how Superfile's prompt mode executes shell commands via Go's exec package. Learn about platform-specific handling, working directory respect, and timeouts for efficient file management.

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

---

**Superfile's prompt command line mode captures raw input from the `:` prompt and executes it through the system shell using Go's `exec` package, with platform-specific handling for Linux/macOS (`/bin/sh`) and Windows (`powershell.exe`), while respecting the focused panel's working directory and configurable timeouts.**

Superfile, an open-source terminal file manager written in Go by `yorukot/superfile`, provides a shell prompt mode that allows users to run arbitrary commands without exiting the TUI. When you type a command after pressing `:` in superfile, the application does not implement its own shell interpreter; instead, it passes the raw command string directly to the host operating system's shell through a carefully orchestrated five-stage pipeline.

## The Execution Pipeline

Superfile's shell command execution follows a defined pipeline that moves from user input capture to result display. Each stage is implemented in specific source files within the repository.

### Step 1: Prompt Parsing in Shell Mode

When a user opens the prompt with the `:` key and enters text, the input is processed by [`src/internal/ui/prompt/utils.go`](https://github.com/yorukot/superfile/blob/main/src/internal/ui/prompt/utils.go) (lines 15‑18). If the prompt is operating in shell mode (the default), the function `getPromptAction` returns a `common.ShellCommandAction` struct containing the raw command string.

```go
// src/internal/ui/prompt/utils.go
return common.ShellCommandAction{
    Command: value, // the raw command string typed by user
}, nil

```

This action encapsulates the user's intent to run a shell command, distinguishing it from other prompt modes like quick navigation or search.

### Step 2: Model Action Dispatch

The main Bubble Tea model in [`src/internal/model.go`](https://github.com/yorukot/superfile/blob/main/src/internal/model.go) (lines 8‑11) receives the `ShellCommandAction` through its action processing loop. When the model encounters this action type, it immediately delegates to `applyShellCommandAction`.

```go
// src/internal/model.go
func (m *model) logAndExecuteAction(action common.ModelAction) (string, tea.Cmd, error) {
    switch action := action.(type) {
    case common.ShellCommandAction:
        m.applyShellCommandAction(action.Command)
        return "", nil, nil
    // other action types...
    }
}

```

This dispatch mechanism keeps the shell execution logic isolated from the main UI update loop.

### Step 3: Shell-Specific Preparation

The `applyShellCommandAction` method retrieves the current working directory from the focused file panel and calls `utils.ExecuteCommandInShell`. This utility function, located in [`src/pkg/utils/shell_utils.go`](https://github.com/yorukot/superfile/blob/main/src/pkg/utils/shell_utils.go) (lines 13‑24), determines the appropriate shell binary based on the operating system: `/bin/sh` for Unix-like systems and `powershell.exe` for Windows.

```go
// src/pkg/utils/shell_utils.go
func ExecuteCommandInShell(timeLimit time.Duration, cmdDir, shellCommand string) (int, string, error) {
    baseCmd := "/bin/sh"
    args := []string{"-c", shellCommand}
    if runtime.GOOS == OsWindows {
        baseCmd = "powershell.exe"
        args[0] = "-Command"
    }
    return ExecuteCommand(timeLimit, cmdDir, baseCmd, args...)
}

```

This abstraction ensures cross-platform compatibility without requiring the caller to handle OS detection.

### Step 4: Process Creation and Execution

The `ExecuteCommand` function in [`src/pkg/utils/shell_utils.go`](https://github.com/yorukot/superfile/blob/main/src/pkg/utils/shell_utils.go) (lines 27‑34) creates a `exec.CommandContext` with a configurable timeout, sets the working directory to the focused panel's location, and detaches the process from the terminal to prevent interference with the TUI's raw mode.

```go
// src/pkg/utils/shell_utils.go
func ExecuteCommand(timeLimit time.Duration, cmdDir, baseCmd string, args ...string) (int, string, error) {
    ctx, cancel := context.WithTimeout(context.Background(), timeLimit)
    defer cancel()
    cmd := exec.CommandContext(ctx, baseCmd, args...)
    cmd.Dir = cmdDir
    DetachFromTerminal(cmd)  // Prevents terminal mode conflicts
    outputBytes, err := cmd.CombinedOutput()
    // Returns exit code, combined stdout/stderr, and error (if timed out or failed)
}

```

The `DetachFromTerminal` call is critical for maintaining UI stability, as it prevents the subprocess from manipulating the terminal settings that superfile's Bubble Tea framework depends on.

### Step 5: Result Handling and Display

After execution completes, `applyShellCommandAction` in [`src/internal/model.go`](https://github.com/yorukot/superfile/blob/main/src/internal/model.go) (lines 35‑44) forwards the exit code and output to the prompt modal via `HandleShellCommandResults`. The modal displays the results or error messages within the superfile interface, keeping the user in the TUI context.

```go
// src/internal/model.go
func (m *model) applyShellCommandAction(shellCommand string) {
    focusPanelDir := m.getFocusedFilePanel().Location
    retCode, output, err := utils.ExecuteCommandInShell(
        common.DefaultCommandTimeout,
        focusPanelDir,
        shellCommand,
    )
    m.promptModal.HandleShellCommandResults(retCode, output)
    if err != nil {
        slog.Error("Command execution failed", "retCode", retCode,
            "error", err, "output", output)
    }
}

```

## Key Source Files and Responsibilities

Understanding superfile's shell execution architecture requires familiarity with these specific files in the `yorukot/superfile` repository:

- **[`src/internal/ui/prompt/utils.go`](https://github.com/yorukot/superfile/blob/main/src/internal/ui/prompt/utils.go)**: Parses prompt input and returns `ShellCommandAction` when operating in shell mode
- **[`src/internal/model.go`](https://github.com/yorukot/superfile/blob/main/src/internal/model.go)**: Receives actions and invokes `applyShellCommandAction` for shell command processing
- **[`src/pkg/utils/shell_utils.go`](https://github.com/yorukot/superfile/blob/main/src/pkg/utils/shell_utils.go)**: Contains `ExecuteCommandInShell` and `ExecuteCommand` with timeout and platform detection logic
- **[`src/internal/common/type.go`](https://github.com/yorukot/superfile/blob/main/src/internal/common/type.go)**: Defines the `ShellCommandAction` struct used throughout the action pipeline
- **[`src/internal/ui/prompt/model.go`](https://github.com/yorukot/superfile/blob/main/src/internal/ui/prompt/model.go)**: Renders the prompt modal and displays execution results via `HandleShellCommandResults`

## Platform-Specific Behavior

Superfile automatically adapts its shell invocation based on the runtime operating system. On Linux and macOS, it uses `/bin/sh -c` to execute commands, while on Windows it switches to `powershell.exe -Command`. This ensures that shell builtins, environment variables, and path handling behave according to user expectations on each platform, without requiring manual configuration.

The working directory is always set to the location of the currently focused file panel, meaning relative paths in your commands resolve correctly against what you see in the UI. The default timeout (defined as `common.DefaultCommandTimeout`) prevents hanging commands from freezing the interface indefinitely.

## Summary

- **Superfile's prompt command line mode** delegates all command execution to the system shell rather than implementing a custom interpreter
- **The execution flow** moves through five stages: prompt parsing, model dispatch, shell preparation (platform detection), process creation (with timeout), and result handling
- **Cross-platform support** is handled automatically via `ExecuteCommandInShell`, selecting `/bin/sh` for Unix systems and `powershell.exe` for Windows
- **Process isolation** via `DetachFromTerminal` ensures the TUI remains responsive and doesn't inherit terminal mode changes from subprocesses
- **Working directory context** is preserved by executing commands in the focused panel's location, with configurable timeouts preventing UI hangs

## Frequently Asked Questions

### How does superfile handle long-running shell commands?

Superfile uses `exec.CommandContext` with a configurable timeout (`common.DefaultCommandTimeout`) to prevent commands from hanging indefinitely. If a command exceeds this limit, the context cancels the process, and superfile returns a timeout error to the prompt modal while logging the failure via `slog.Error`. You can adjust this timeout in the configuration if you need to run longer operations.

### Can I use shell aliases and functions in superfile's prompt mode?

Yes, since superfile executes commands through `/bin/sh` (or `powershell.exe` on Windows), any aliases or functions defined in your shell's configuration files will be available only if they are loaded by the shell binary being invoked. However, because superfile uses non-interactive shell invocation (typically `/bin/sh -c`), your `.bashrc` or `.zshrc` may not be sourced automatically. For full alias support, you would need to invoke an interactive shell or source your configuration files within the command.

### Why does superfile use `/bin/sh` instead of the user's default shell on Linux?

Superfile defaults to `/bin/sh` for portability and consistency across different Linux distributions and Unix systems. While your interactive shell might be zsh or fish, `/bin/sh` is guaranteed to exist on POSIX-compliant systems and provides a predictable execution environment. This ensures that superfile's prompt command line mode behaves consistently regardless of the user's preferred interactive shell.

### Where is the shell command output displayed in superfile?

The output appears in the prompt modal itself through the `HandleShellCommandResults` method in [`src/internal/ui/prompt/model.go`](https://github.com/yorukot/superfile/blob/main/src/internal/ui/prompt/model.go). After execution completes, superfile displays the combined stdout and stderr output directly in the prompt area, along with the exit code. If the command fails (non-zero exit code), the error is logged internally, but the output is still presented to the user within the modal interface.