How to Add Custom File Open Commands by Extension Using `open_with` in Superfile
Configure the [open_with] table in superfile.toml to map file extensions to custom commands, then press Enter on any matching file to open it with your specified program instead of the system default.
Superfile is a terminal-based file manager that allows you to override the default application associations on Linux and macOS using the open_with configuration option. By defining extension-to-command mappings, you can ensure that pressing Enter on a file automatically launches it with your preferred editor or viewer.
Understanding the open_with Configuration Structure
The custom command mappings are stored in the ConfigType struct defined in src/internal/common/config_type.go. According to the source code, the relevant field is an OpenWith map with the signature map[string]string (lines 71-73), where keys are file extensions and values are shell commands.
When superfile initializes, it parses the superfile.toml configuration file and populates this map. The feature is platform-aware: the lookup logic runs on macOS and Linux, while Windows relies on its native system handlers (though you can still manually configure entries for consistency).
The TOML Syntax
In your superfile.toml file, define an [open_with] table. Each key represents a file extension without the leading dot, and each value specifies the exact command that will receive the file path as its sole argument:
[open_with]
txt = "code --new-window"
md = "code"
pdf = "zathura"
After saving the configuration, restart superfile or trigger a config reload to activate the new mappings.
How Command Resolution Works
When you select a file and press Enter, the model.enterPanel method calls model.executeOpenCommand in src/internal/handle_panel_movement.go (lines 93-99). The function extracts the extension, normalizes it to lowercase, and checks for a custom match:
ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(filePath), "."))
if extEditor, ok := common.Config.OpenWith[ext]; ok {
openCommand = extEditor
}
cmd := exec.Command(openCommand, filePath)
utils.DetachFromTerminal(cmd)
cmd.Start()
The lookup strips the dot from filepath.Ext(), converts the result to lowercase for case-insensitive matching, and checks against common.Config.OpenWith. If a match exists, it replaces the default xdg-open (Linux) or open (macOS) command with your custom one. The command is then executed in a detached process so superfile remains responsive.
Practical Configuration Examples
Here are common patterns for mapping extensions to specific applications:
Open Markdown files in Visual Studio Code:
[open_with]
md = "code"
Open PDFs with Zathura on Linux:
[open_with]
pdf = "zathura"
Open plain text files with TextEdit on macOS:
[open_with]
txt = "open -a TextEdit"
Open JSON files with a specific IDE flags:
[open_with]
json = "code --goto"
Note that the command string is passed directly to exec.Command with the file path as the final argument. You do not need to include placeholders like %f or $1; superfile automatically appends the target file path.
Platform-Specific Behavior
The open_with feature is primarily implemented for Unix-like systems. On Linux and macOS, superfile uses the resolution logic shown above to determine whether to use a custom command or fall back to system defaults.
On Windows, the application relies on the operating system's file associations by default. However, the OpenWith map is still available in the configuration structure, and you can define entries for Windows-specific commands if you modify the execution flow or if future updates expand platform support. For cross-platform consistency, keeping your [open_with] table synchronized across all your configuration files ensures predictable behavior.
Summary
- Configuration Location: The
OpenWithmap is defined insrc/internal/common/config_type.goand populated fromsuperfile.toml. - Syntax: Use the
[open_with]TOML table with extension names (without dots) as keys and commands as values. - Execution: The lookup occurs in
src/internal/handle_panel_movement.gowhen pressing Enter, replacing the defaultxdg-openoropencommand with your custom entry. - Case Handling: Extensions are normalized to lowercase automatically, so
PDFandpdfentries are equivalent. - Reload Required: Changes take effect only after restarting superfile or reloading the configuration.
Frequently Asked Questions
How do I open files with Neovim using open_with?
Add the extension and the terminal editor command to your superfile.toml. Since superfile detaches the process from the terminal, you should use a terminal emulator wrapper or a GUI version:
[open_with]
txt = "alacritty -e nvim"
md = "alacritty -e nvim"
The file path is appended automatically, so nvim receives the correct target.
Does open_with support wildcard patterns or full filenames?
No. As implemented in src/internal/handle_panel_movement.go, the lookup only matches against the file extension extracted by filepath.Ext(). It does not support glob patterns, regex, or full filename matching like Makefile or Dockerfile. You must specify the exact extension key (e.g., mk for Makefiles).
Why isn't my custom command working on Windows?
The current implementation in the superfile source code routes Windows file opening through the native system handler before checking the OpenWith map in certain builds. Ensure you are running the latest version, and verify that your command is in the system PATH. For Windows-specific customization, you may need to use the Windows start command wrapper or wait for future platform parity updates.
Can I pass multiple arguments to the command?
Yes. The value in the TOML table is split into the command name and arguments when passed to exec.Command. For example, txt = "code --wait --new-window" will pass --wait, --new-window, and the file path as separate arguments to the executable. Avoid shell-specific syntax like pipes or redirects, as the command is executed directly without a shell interpreter.
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 →