Skip to content

Commit

Permalink
OpenFileManager for opening with the native file manager and optional
Browse files Browse the repository at this point in the history
file selection support

Closes #3197
  • Loading branch information
Krzysztofz01 authored and rcalixte committed Dec 7, 2024
1 parent 2e4fce7 commit fcf7da2
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 10 deletions.
1 change: 1 addition & 0 deletions mkdocs-website/docs/en/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- `app.OpenDirectory(dir string)` to open the system file explorer to the directory `dir` by [@leaanthony](https://github.com/leaanthony)
- `app.OpenFileManager(path string)` to open file manager to the path `path` with optional highlighting via `selectFile` by [@Krzysztofz01](https://github.com/Krzysztofz01)[@rcalixte](https://github.com/rcalixte)

### Fixed

Expand Down
110 changes: 103 additions & 7 deletions v3/internal/fileexplorer/fileexplorer.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,120 @@
package fileexplorer

import (
"bytes"
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"

ini "gopkg.in/ini.v1"
)

func Open(path string) error {
var cmd *exec.Cmd
type explorerBinArgs func(path string, selectFile bool) (string, []string, error)

func OpenFileManager(path string, selectFile bool) error {
path = os.ExpandEnv(path)
if pathInfo, err := os.Stat(path); err != nil {
return fmt.Errorf("failed to access the specified path stat: %w", err)
} else {
selectFile = selectFile && !pathInfo.IsDir()
}

var (
explorerBinArgs explorerBinArgs
ignoreExitCode bool = false
)

switch runtime.GOOS {
case "windows":
cmd = exec.Command("explorer", path)
explorerBinArgs = windowsExplorerBinArgs
// NOTE: Disabling the exit code check on Windows system. Workaround for explorer.exe
// exit code handling (https://github.com/microsoft/WSL/issues/6565)
ignoreExitCode = true
case "darwin":
cmd = exec.Command("open", path)
explorerBinArgs = darwinExplorerBinArgs
case "linux":
cmd = exec.Command("xdg-open", path)
explorerBinArgs = linuxExplorerBinArgs
default:
return fmt.Errorf("unsupported platform")
return errors.New("unsupported platform")
}

return cmd.Run()
explorerBin, explorerArgs, err := explorerBinArgs(path, selectFile)
if err != nil {
return fmt.Errorf("failed to determine the file explorer binary: %w", err)
}

cmd := exec.Command(explorerBin, explorerArgs...)
cmd.Stdout = nil
cmd.Stderr = nil

if err := cmd.Run(); err != nil {
if !ignoreExitCode {
return fmt.Errorf("failed to open the file explorer: %w", err)
}
}
return nil
}

var windowsExplorerBinArgs explorerBinArgs = func(path string, selectFile bool) (string, []string, error) {
args := []string{}
if selectFile {
args = append(args, fmt.Sprintf("/select,\"%s\"", path))
} else {
args = append(args, path)
}
return "explorer.exe", args, nil
}

var darwinExplorerBinArgs explorerBinArgs = func(path string, selectFile bool) (string, []string, error) {
args := []string{}
if selectFile {
args = append(args, "-R")
}

args = append(args, path)
return "open", args, nil
}

var linuxExplorerBinArgs explorerBinArgs = func(path string, selectFile bool) (string, []string, error) {
fileManagerQuery := exec.Command("xdg-mime", "query", "default", "inode/directory")
buf := new(bytes.Buffer)
fileManagerQuery.Stdout = buf
fileManagerQuery.Stderr = nil

if err := fileManagerQuery.Run(); err == nil {
var desktopFile string
xdgPath := strings.TrimSpace(os.Getenv("XDG_DATA_HOME"))
if xdgPath == "" {
desktopFile = os.Getenv("HOME") + "/.local/share/applications"
}
desktopFile = xdgPath + strings.TrimSpace((buf.String()))

if _, err := os.Stat(desktopFile); err != nil {
desktopFile = "/usr/share/applications" + strings.TrimSpace((buf.String()))
}

cfg, err := ini.Load(desktopFile)
if err != nil {
// Opting to fallback rather than fail
return linuxFallbackExplorerBinArgs(path, selectFile)
}

exec := cfg.Section("Desktop Entry").Key("Exec").String()
args := strings.Split(exec, " ")
args = append(args, path)

return args[0], args[1:], nil
} else {
return linuxFallbackExplorerBinArgs(path, selectFile)
}
}

var linuxFallbackExplorerBinArgs explorerBinArgs = func(path string, selectFile bool) (string, []string, error) {
// NOTE: The linux fallback explorer opening is not supporting file selection
path = filepath.Dir(path)
return "xdg-open", []string{path}, nil
}
7 changes: 4 additions & 3 deletions v3/pkg/application/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"embed"
"encoding/json"
"fmt"
"github.com/wailsapp/wails/v3/internal/fileexplorer"
"io"
"log"
"log/slog"
Expand All @@ -17,6 +16,8 @@ import (
"strings"
"sync"

"github.com/wailsapp/wails/v3/internal/fileexplorer"

"github.com/wailsapp/wails/v3/internal/operatingsystem"

"github.com/pkg/browser"
Expand Down Expand Up @@ -1046,8 +1047,8 @@ func (a *App) Paths(selector Paths) []string {
return pathdirs[selector]
}

func (a *App) OpenDirectory(path string) error {
func (a *App) OpenDirectory(path string, selectFile bool) error {
return InvokeSyncWithError(func() error {
return fileexplorer.Open(path)
return fileexplorer.OpenFileManager(path, selectFile)
})
}

0 comments on commit fcf7da2

Please sign in to comment.