pinakes/crates/pinakes-core/src/opener.rs
NotAShelf 6a73d11c4b
initial commit
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I4a6b498153eccd5407510dd541b7f4816a6a6964
2026-01-31 15:20:30 +03:00

79 lines
2.1 KiB
Rust

use std::path::Path;
use std::process::Command;
use crate::error::{PinakesError, Result};
pub trait Opener: Send + Sync {
fn open(&self, path: &Path) -> Result<()>;
}
/// Linux opener using xdg-open
pub struct XdgOpener;
impl Opener for XdgOpener {
fn open(&self, path: &Path) -> Result<()> {
let status = Command::new("xdg-open")
.arg(path)
.status()
.map_err(|e| PinakesError::InvalidOperation(format!("failed to run xdg-open: {e}")))?;
if status.success() {
Ok(())
} else {
Err(PinakesError::InvalidOperation(format!(
"xdg-open exited with status {status}"
)))
}
}
}
/// macOS opener using the `open` command
pub struct MacOpener;
impl Opener for MacOpener {
fn open(&self, path: &Path) -> Result<()> {
let status = Command::new("open")
.arg(path)
.status()
.map_err(|e| PinakesError::InvalidOperation(format!("failed to run open: {e}")))?;
if status.success() {
Ok(())
} else {
Err(PinakesError::InvalidOperation(format!(
"open exited with status {status}"
)))
}
}
}
/// Windows opener using `cmd /c start`
pub struct WindowsOpener;
impl Opener for WindowsOpener {
fn open(&self, path: &Path) -> Result<()> {
let status = Command::new("cmd")
.args(["/C", "start", ""])
.arg(path)
.status()
.map_err(|e| {
PinakesError::InvalidOperation(format!("failed to run cmd /c start: {e}"))
})?;
if status.success() {
Ok(())
} else {
Err(PinakesError::InvalidOperation(format!(
"cmd /c start exited with status {status}"
)))
}
}
}
/// Returns the platform-appropriate opener.
pub fn default_opener() -> Box<dyn Opener> {
if cfg!(target_os = "macos") {
Box::new(MacOpener)
} else if cfg!(target_os = "windows") {
Box::new(WindowsOpener)
} else {
Box::new(XdgOpener)
}
}