use std::path::Path;
pub fn open_file(path: &Path) -> Result<(), String> {
#[cfg(windows)]
{
windows::open(path)
}
#[cfg(not(windows))]
{
let mut command = if cfg!(target_os = "macos") {
let mut open = std::process::Command::new("open");
open.arg("-t");
open
} else {
std::process::Command::new("xdg-open")
};
command
.arg(path)
.spawn()
.map(drop)
.map_err(|err| format!("cannot open {}: {err}", path.display()))
}
}
pub fn open_folder(folder: &Path) -> Result<(), String> {
let program = if cfg!(windows) {
"explorer"
} else if cfg!(target_os = "macos") {
"open"
} else {
"xdg-open"
};
std::process::Command::new(program)
.arg(folder)
.spawn()
.map(drop)
.map_err(|err| format!("cannot open {}: {err}", folder.display()))
}
#[cfg(windows)]
mod windows {
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use std::path::Path;
const SE_ERR_NOASSOC: isize = 31;
pub fn open(path: &Path) -> Result<(), String> {
use windows_sys::Win32::UI::Shell::ShellExecuteW;
use windows_sys::Win32::UI::WindowsAndMessaging::SW_SHOWNORMAL;
let wide = |s: &OsStr| s.encode_wide().chain(Some(0)).collect::<Vec<u16>>();
let verb = wide(OsStr::new("open"));
let file = wide(path.as_os_str());
let result = unsafe {
ShellExecuteW(
std::ptr::null_mut(),
verb.as_ptr(),
file.as_ptr(),
std::ptr::null(),
std::ptr::null(),
SW_SHOWNORMAL,
)
} as isize;
match result {
r if r > 32 => Ok(()),
SE_ERR_NOASSOC => std::process::Command::new("notepad.exe")
.arg(path)
.spawn()
.map(drop)
.map_err(|err| format!("cannot open {} in Notepad: {err}", path.display())),
r => Err(format!("cannot open {} (error {r})", path.display())),
}
}
}