diff --git a/src/haiku.rs b/src/haiku.rs index 38bbf33..7c728d6 100644 --- a/src/haiku.rs +++ b/src/haiku.rs @@ -5,13 +5,21 @@ use crate::{CommandExt, IntoResult}; pub fn that>(path: T) -> io::Result<()> { Command::new("/bin/open") .arg(path.as_ref()) - .status_without_output() + .without_io() + .status() .into_result() } pub fn with>(path: T, app: impl Into) -> io::Result<()> { Command::new(app.into()) .arg(path.as_ref()) - .status_without_output() + .without_io() + .status() .into_result() } + +pub fn commands>(path: T) -> impl Iterator { + let mut cmd = Command::new("/bin/open"); + cmd.arg(path.as_ref()); + Some(cmd).into_iter() +} diff --git a/src/ios.rs b/src/ios.rs index 179bf70..bd0938e 100644 --- a/src/ios.rs +++ b/src/ios.rs @@ -6,7 +6,8 @@ pub fn that>(path: T) -> io::Result<()> { Command::new("uiopen") .arg("--url") .arg(path.as_ref()) - .status_without_output() + .without_io() + .status() .into_result() } @@ -16,6 +17,13 @@ pub fn with>(path: T, app: impl Into) -> io::Result<()> .arg(path.as_ref()) .arg("--bundleid") .arg(app.into()) - .status_without_output() + .without_io() + .status() .into_result() } + +pub fn commands>(path: T) -> impl Iterator { + let mut cmd = Command::new("uiopen"); + cmd.arg("--url").arg(path.as_ref()); + Some(cmd).into_iter() +} diff --git a/src/lib.rs b/src/lib.rs index 256ea15..f71bd35 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,12 @@ //! open::with("http://rust-lang.org", "firefox").unwrap(); //! ``` //! +//! Or obtain commands for opening the URL without running them. +//! +//! ```no_run +//! let cmds = open::commands("http://rust-lang.org"); +//! ``` +//! //! # Notes //! //! ## Nonblocking operation @@ -131,6 +137,21 @@ pub fn with>(path: T, app: impl Into) -> io::Result<()> os::with(path, app) } +/// Get iterator over commands that open path with the default application. +/// Iterator over Commands is returned as for certain platforms there are +/// multiple command options. +/// It is the responsibility of the callee to try all commands. +/// +/// # Examples +/// +/// ```no_run +/// let path = "http://rust-lang.org"; +/// let cmds = open::commands(path); +/// ``` +pub fn commands>(path: T) -> impl Iterator { + os::commands(path) +} + /// Open path with the default application in a new thread. /// /// See documentation of [`that()`] for more details. @@ -182,17 +203,19 @@ impl IntoResult> for std::os::raw::c_int { } trait CommandExt { - fn status_without_output(&mut self) -> io::Result; + fn without_io(&mut self) -> &mut Self; + fn status(&mut self) -> io::Result; } impl CommandExt for Command { - fn status_without_output(&mut self) -> io::Result { - let mut process = self - .stdin(Stdio::null()) + fn without_io(&mut self) -> &mut Self { + self.stdin(Stdio::null()) .stdout(Stdio::null()) .stderr(Stdio::null()) - .spawn()?; + } + fn status(&mut self) -> io::Result { + let mut process = self.spawn()?; process.wait() } } diff --git a/src/macos.rs b/src/macos.rs index 2575d58..4c98f1a 100644 --- a/src/macos.rs +++ b/src/macos.rs @@ -5,7 +5,8 @@ use crate::{CommandExt, IntoResult}; pub fn that>(path: T) -> io::Result<()> { Command::new("/usr/bin/open") .arg(path.as_ref()) - .status_without_output() + .without_io() + .status() .into_result() } @@ -14,6 +15,13 @@ pub fn with>(path: T, app: impl Into) -> io::Result<()> .arg(path.as_ref()) .arg("-a") .arg(app.into()) - .status_without_output() + .without_io() + .status() .into_result() } + +pub fn commands>(path: T) -> impl Iterator { + let mut cmd = Command::new("/usr/bin/open"); + cmd.arg(path.as_ref()); + Some(cmd).into_iter() +} diff --git a/src/unix.rs b/src/unix.rs index 1c807ef..fad8541 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -8,7 +8,7 @@ use std::{ use crate::{CommandExt, IntoResult}; -pub fn that>(path: T) -> io::Result<()> { +pub fn commands>(path: T) -> impl Iterator { let path = path.as_ref(); let open_handlers = [ ("xdg-open", &[path] as &[_]), @@ -18,12 +18,19 @@ pub fn that>(path: T) -> io::Result<()> { ("wslview", &[&wsl_path(path)]), ]; + open_handlers.into_iter().map(|&(cmd, args)| { + let mut cmd = Command::new("/usr/bin/open"); + cmd.args(args); + cmd + }) +} + +pub fn that>(path: T) -> io::Result<()> { let mut unsuccessful = None; let mut io_error = None; - for (command, args) in &open_handlers { - let result = Command::new(command).args(*args).status_without_output(); - + for cmd in commands(path) { + let result = cmd.without_io().status().into_result(); match result { Ok(status) if status.success() => return Ok(()), Ok(status) => { @@ -46,7 +53,8 @@ pub fn that>(path: T) -> io::Result<()> { pub fn with>(path: T, app: impl Into) -> io::Result<()> { Command::new(app.into()) .arg(path.as_ref()) - .status_without_output() + .without_io() + .status() .into_result() } diff --git a/src/windows.rs b/src/windows.rs index b2b8658..ed5fbb9 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -1,21 +1,28 @@ -use std::{ffi::OsStr, io}; +use std::{ffi::OsStr, io, process::Command}; use crate::{CommandExt, IntoResult}; pub fn that>(path: T) -> io::Result<()> { - std::process::Command::new("cmd") + Command::new("cmd") .arg("/c") .arg("start") .arg(path.as_ref()) - .status_without_output() - .into_result() + .without_io() + .status() } pub fn with>(path: T, app: impl Into) -> io::Result<()> { - std::process::Command::new("cmd") + Command::new("cmd") .arg("/c") .arg(app.into()) .arg(path.as_ref()) - .status_without_output() + .without_io() + .status() .into_result() } + +pub fn commands>(path: T) -> impl Iterator { + let mut cmd = Command::new("cmd"); + cmd.arg("/c").arg("start").arg(path.as_ref()); + Some(cmd).into_iter() +}