1use std::{
2 env,
3 ffi::{OsStr, OsString},
4 io,
5 path::{Path, PathBuf},
6 process::Command,
7};
8
9use crate::{CommandExt, IntoResult};
10
11pub fn that<T: AsRef<OsStr>>(path: T) -> io::Result<()> {
12 let path = path.as_ref();
13 let open_handlers = [
14 ("xdg-open", &[path] as &[_]),
15 ("gio", &[OsStr::new("open"), path]),
16 ("gnome-open", &[path]),
17 ("kde-open", &[path]),
18 ("wslview", &[&wsl_path(path)]),
19 ];
20
21 let mut unsuccessful = None;
22 let mut io_error = None;
23
24 for (command, args) in &open_handlers {
25 let result = Command::new(command).args(*args).status_without_output();
26
27 match result {
28 Ok(status) if status.success() => return Ok(()),
29 Ok(status) => {
30 unsuccessful = unsuccessful.or_else(|| {
31 Some(std::io::Error::new(
32 std::io::ErrorKind::Other,
33 status.to_string(),
34 ))
35 })
36 }
37 Err(err) => io_error = io_error.or(Some(err)),
38 }
39 }
40
41 Err(unsuccessful
42 .or(io_error)
43 .expect("successful cases don't get here"))
44}
45
46pub fn with<T: AsRef<OsStr>>(path: T, app: impl Into<String>) -> io::Result<()> {
47 Command::new(app.into())
48 .arg(path.as_ref())
49 .status_without_output()
50 .into_result()
51}
52
53fn wsl_path<T: AsRef<OsStr>>(path: T) -> OsString {
59 fn path_relative_to_current_dir<T: AsRef<OsStr>>(path: T) -> Option<PathBuf> {
60 let path = Path::new(&path);
61
62 if path.is_relative() {
63 return None;
64 }
65
66 let base = env::current_dir().ok()?;
67 pathdiff::diff_paths(path, base)
68 }
69
70 match path_relative_to_current_dir(&path) {
71 None => OsString::from(&path),
72 Some(relative) => OsString::from(relative),
73 }
74}