diff --git a/internal/app/app.go b/internal/app/app.go index a643b0d..31d2d17 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -581,6 +581,9 @@ func (m *Model) fileActionCmd(path string, action string) tea.Cmd { case "edit": return editFileCmd(path) case "preview": + if m.cfg.Behavior.ViewMode == "system" { + return openSystemDefaultCmd(path) + } return viewFileCmd(path) default: return editFileCmd(path) @@ -699,7 +702,11 @@ func (m Model) startView() (tea.Model, tea.Cmd) { if e == nil || e.IsDir() { return m, nil } - return m, viewFileCmd(m.currentFilePath()) + path := m.currentFilePath() + if m.cfg.Behavior.ViewMode == "system" { + return m, openSystemDefaultCmd(path) + } + return m, viewFileCmd(path) } func (m Model) startEdit() (tea.Model, tea.Cmd) { diff --git a/internal/app/commands.go b/internal/app/commands.go index a8abd75..7d9e015 100644 --- a/internal/app/commands.go +++ b/internal/app/commands.go @@ -5,6 +5,7 @@ import ( "os" "os/exec" "path/filepath" + "runtime" "strings" tea "github.com/charmbracelet/bubbletea" @@ -78,6 +79,22 @@ func externalCmd(envVar, fallback, path string) tea.Cmd { }) } +func openSystemDefaultCmd(path string) tea.Cmd { + return func() tea.Msg { + var c *exec.Cmd + switch runtime.GOOS { + case "darwin": + c = exec.Command("open", path) + case "windows": + c = exec.Command("explorer", path) + default: + c = exec.Command("xdg-open", path) + } + _ = c.Start() + return externalDoneMsg{} + } +} + func executeFileCmd(path string, dir string, pause bool) tea.Cmd { if pause { shell := os.Getenv("SHELL") diff --git a/internal/config/config.go b/internal/config/config.go index c05c2ee..d0d70cd 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -24,6 +24,8 @@ type BehaviorConfig struct { EnterAction string `toml:"enter_action"` // What Space does on a file: "preview" (default) or "edit" SpaceAction string `toml:"space_action"` + // ViewMode controls how F3 opens files: "pager" (default, uses $PAGER/less) or "system" (OS default app) + ViewMode string `toml:"view_mode"` // Whether to ask for confirmation before executing a file. ConfirmExecute *bool `toml:"confirm_execute"` // Whether to pause and wait after execution before returning to Midday Commander. @@ -103,9 +105,10 @@ func Default() Config { return Config{ Theme: "", Behavior: BehaviorConfig{ - EnterAction: "edit", - SpaceAction: "preview", - ConfirmExecute: boolPtr(true), + EnterAction: "edit", + SpaceAction: "preview", + ViewMode: "pager", + ConfirmExecute: boolPtr(true), PauseAfterExecute: false, ShowHidden: boolPtr(true), }, @@ -178,13 +181,16 @@ func Load() Config { if fileCfg.Behavior.SpaceAction != "" { cfg.Behavior.SpaceAction = fileCfg.Behavior.SpaceAction } - if fileCfg.Behavior.ConfirmExecute != nil { - cfg.Behavior.ConfirmExecute = fileCfg.Behavior.ConfirmExecute - } - cfg.Behavior.PauseAfterExecute = fileCfg.Behavior.PauseAfterExecute - if fileCfg.Behavior.ShowHidden != nil { - cfg.Behavior.ShowHidden = fileCfg.Behavior.ShowHidden - } + if fileCfg.Behavior.ViewMode != "" { + cfg.Behavior.ViewMode = fileCfg.Behavior.ViewMode + } + if fileCfg.Behavior.ConfirmExecute != nil { + cfg.Behavior.ConfirmExecute = fileCfg.Behavior.ConfirmExecute + } + cfg.Behavior.PauseAfterExecute = fileCfg.Behavior.PauseAfterExecute + if fileCfg.Behavior.ShowHidden != nil { + cfg.Behavior.ShowHidden = fileCfg.Behavior.ShowHidden + } mergeKeys(&cfg.Keys, &fileCfg.Keys) normalizeAllKeys(&cfg.Keys)