Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
Make clear which operating systems we support in the file system.
  • Loading branch information
Byron committed Jun 12, 2022
1 parent 0bdc6d6 commit 475f002
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 198 deletions.
17 changes: 17 additions & 0 deletions src/haiku.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use std::{ffi::OsStr, io, process::Command};

use crate::{CommandExt, IntoResult};

pub fn that<T: AsRef<OsStr>>(path: T) -> io::Result<()> {
Command::new("/bin/open")
.arg(path.as_ref())
.status_without_output()
.into_result()
}

pub fn with<T: AsRef<OsStr>>(path: T, app: impl Into<String>) -> io::Result<()> {
Command::new(app.into())
.arg(path.as_ref())
.status_without_output()
.into_result()
}
21 changes: 21 additions & 0 deletions src/ios.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use std::{ffi::OsStr, io, process::Command};

use crate::{CommandExt, IntoResult};

pub fn that<T: AsRef<OsStr>>(path: T) -> io::Result<()> {
Command::new("uiopen")
.arg("--url")
.arg(path.as_ref())
.status_without_output()
.into_result()
}

pub fn with<T: AsRef<OsStr>>(path: T, app: impl Into<String>) -> io::Result<()> {
Command::new("uiopen")
.arg("--url")
.arg(path.as_ref())
.arg("--bundleid")
.arg(app.into())
.status_without_output()
.into_result()
}
203 changes: 5 additions & 198 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,134 +183,16 @@ impl CommandExt for Command {
}

#[cfg(windows)]
mod windows {
use std::{ffi::OsStr, io, os::windows::ffi::OsStrExt, ptr};

use std::os::raw::c_int;
use windows_sys::Win32::UI::Shell::ShellExecuteW;

use crate::IntoResult;

fn convert_path(path: &OsStr) -> io::Result<Vec<u16>> {
let mut maybe_result: Vec<_> = path.encode_wide().collect();
if maybe_result.iter().any(|&u| u == 0) {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"path contains NUL byte(s)",
));
}
maybe_result.push(0);
Ok(maybe_result)
}

pub fn that<T: AsRef<OsStr>>(path: T) -> io::Result<()> {
const SW_SHOW: c_int = 5;

let path = convert_path(path.as_ref())?;
let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
let result = unsafe {
ShellExecuteW(
0,
operation.as_ptr(),
path.as_ptr(),
ptr::null(),
ptr::null(),
SW_SHOW,
)
};
(result as c_int).into_result()
}

pub fn with<T: AsRef<OsStr>>(path: T, app: impl Into<String>) -> io::Result<()> {
const SW_SHOW: c_int = 5;

let path = convert_path(path.as_ref())?;
let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
let app_name: Vec<u16> = OsStr::new(&format!("{}\0", app.into()))
.encode_wide()
.collect();
let result = unsafe {
ShellExecuteW(
0,
operation.as_ptr(),
app_name.as_ptr(),
path.as_ptr(),
ptr::null(),
SW_SHOW,
)
};
(result as c_int).into_result()
}
}
mod windows;

#[cfg(target_os = "macos")]
mod macos {
use std::{ffi::OsStr, io, process::Command};

use crate::{CommandExt, IntoResult};

pub fn that<T: AsRef<OsStr>>(path: T) -> io::Result<()> {
Command::new("/usr/bin/open")
.arg(path.as_ref())
.status_without_output()
.into_result()
}

pub fn with<T: AsRef<OsStr>>(path: T, app: impl Into<String>) -> io::Result<()> {
Command::new("/usr/bin/open")
.arg(path.as_ref())
.arg("-a")
.arg(app.into())
.status_without_output()
.into_result()
}
}
mod macos;

#[cfg(target_os = "ios")]
mod ios {
use std::{ffi::OsStr, io, process::Command};

use crate::{CommandExt, IntoResult};

pub fn that<T: AsRef<OsStr>>(path: T) -> io::Result<()> {
Command::new("uiopen")
.arg("--url")
.arg(path.as_ref())
.status_without_output()
.into_result()
}

pub fn with<T: AsRef<OsStr>>(path: T, app: impl Into<String>) -> io::Result<()> {
Command::new("uiopen")
.arg("--url")
.arg(path.as_ref())
.arg("--bundleid")
.arg(app.into())
.status_without_output()
.into_result()
}
}
mod ios;

#[cfg(target_os = "haiku")]
mod haiku {
use std::{ffi::OsStr, io, process::Command};

use crate::{CommandExt, IntoResult};

pub fn that<T: AsRef<OsStr>>(path: T) -> io::Result<()> {
Command::new("/bin/open")
.arg(path.as_ref())
.status_without_output()
.into_result()
}

pub fn with<T: AsRef<OsStr>>(path: T, app: impl Into<String>) -> io::Result<()> {
Command::new(app.into())
.arg(path.as_ref())
.status_without_output()
.into_result()
}
}
mod haiku;

#[cfg(any(
target_os = "linux",
Expand All @@ -322,79 +204,4 @@ mod haiku {
target_os = "illumos",
target_os = "solaris"
))]
mod unix {
use std::{
env,
ffi::{OsStr, OsString},
io,
path::{Path, PathBuf},
process::Command,
};

use crate::{CommandExt, IntoResult};

pub fn that<T: AsRef<OsStr>>(path: T) -> io::Result<()> {
let path = path.as_ref();
let open_handlers = [
("xdg-open", &[path] as &[_]),
("gio", &[OsStr::new("open"), path]),
("gnome-open", &[path]),
("kde-open", &[path]),
("wslview", &[&wsl_path(path)]),
];

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();

match result {
Ok(status) if status.success() => return Ok(()),
Ok(status) => {
unsuccessful = unsuccessful.or_else(|| {
Some(std::io::Error::new(
std::io::ErrorKind::Other,
status.to_string(),
))
})
}
Err(err) => io_error = io_error.or(Some(err)),
}
}

Err(unsuccessful
.or(io_error)
.expect("successful cases don't get here"))
}

pub fn with<T: AsRef<OsStr>>(path: T, app: impl Into<String>) -> io::Result<()> {
Command::new(app.into())
.arg(path.as_ref())
.status_without_output()
.into_result()
}

// Polyfill to workaround absolute path bug in wslu(wslview). In versions before
// v3.1.1, wslview is unable to find absolute paths. `wsl_path` converts an
// absolute path into a relative path starting from the current directory. If
// the path is already a relative path or the conversion fails the original path
// is returned.
fn wsl_path<T: AsRef<OsStr>>(path: T) -> OsString {
fn path_relative_to_current_dir<T: AsRef<OsStr>>(path: T) -> Option<PathBuf> {
let path = Path::new(&path);

if path.is_relative() {
return None;
}

let base = env::current_dir().ok()?;
pathdiff::diff_paths(path, base)
}

match path_relative_to_current_dir(&path) {
None => OsString::from(&path),
Some(relative) => OsString::from(relative),
}
}
}
mod unix;
19 changes: 19 additions & 0 deletions src/macos.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use std::{ffi::OsStr, io, process::Command};

use crate::{CommandExt, IntoResult};

pub fn that<T: AsRef<OsStr>>(path: T) -> io::Result<()> {
Command::new("/usr/bin/open")
.arg(path.as_ref())
.status_without_output()
.into_result()
}

pub fn with<T: AsRef<OsStr>>(path: T, app: impl Into<String>) -> io::Result<()> {
Command::new("/usr/bin/open")
.arg(path.as_ref())
.arg("-a")
.arg(app.into())
.status_without_output()
.into_result()
}
74 changes: 74 additions & 0 deletions src/unix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use std::{
env,
ffi::{OsStr, OsString},
io,
path::{Path, PathBuf},
process::Command,
};

use crate::{CommandExt, IntoResult};

pub fn that<T: AsRef<OsStr>>(path: T) -> io::Result<()> {
let path = path.as_ref();
let open_handlers = [
("xdg-open", &[path] as &[_]),
("gio", &[OsStr::new("open"), path]),
("gnome-open", &[path]),
("kde-open", &[path]),
("wslview", &[&wsl_path(path)]),
];

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();

match result {
Ok(status) if status.success() => return Ok(()),
Ok(status) => {
unsuccessful = unsuccessful.or_else(|| {
Some(std::io::Error::new(
std::io::ErrorKind::Other,
status.to_string(),
))
})
}
Err(err) => io_error = io_error.or(Some(err)),
}
}

Err(unsuccessful
.or(io_error)
.expect("successful cases don't get here"))
}

pub fn with<T: AsRef<OsStr>>(path: T, app: impl Into<String>) -> io::Result<()> {
Command::new(app.into())
.arg(path.as_ref())
.status_without_output()
.into_result()
}

// Polyfill to workaround absolute path bug in wslu(wslview). In versions before
// v3.1.1, wslview is unable to find absolute paths. `wsl_path` converts an
// absolute path into a relative path starting from the current directory. If
// the path is already a relative path or the conversion fails the original path
// is returned.
fn wsl_path<T: AsRef<OsStr>>(path: T) -> OsString {
fn path_relative_to_current_dir<T: AsRef<OsStr>>(path: T) -> Option<PathBuf> {
let path = Path::new(&path);

if path.is_relative() {
return None;
}

let base = env::current_dir().ok()?;
pathdiff::diff_paths(path, base)
}

match path_relative_to_current_dir(&path) {
None => OsString::from(&path),
Some(relative) => OsString::from(relative),
}
}
Loading

0 comments on commit 475f002

Please sign in to comment.