Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve support for wsl. #33

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ name = "open"
winapi = { version = "0.3", features = ["shellapi"] }

[target.'cfg(all(unix, not(macos)))'.dependencies]
which = "4"
pathdiff = "0.2.0"
88 changes: 60 additions & 28 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,40 +244,72 @@ mod ios {
))]
mod unix {
use std::{
ffi::OsStr,
io::{Error, Result},
env,
ffi::{OsStr, OsString},
io,
path::{Path, PathBuf},
process::{Command, ExitStatus, Stdio},
};

use which::which;
pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> io::Result<ExitStatus> {
let path = path.as_ref();
let open_handlers = [
("xdg-open", &[path] as &[_]),
Byron marked this conversation as resolved.
Show resolved Hide resolved
("gio", &[OsStr::new("open"), path]),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seeing this implies that the previous invocation never worked, which is reflected in its man page.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gio open works in the old code. The problem is that wsl Ubuntu is not setup with file handlers by default. Ubuntu not under wsl works as expected.

("gnome-open", &[path]),
("kde-open", &[path]),
("wslview", &[&wsl_path(path)]),
];

pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result<ExitStatus> {
["xdg-open", "gio", "gnome-open", "kde-open", "wslview"] // Open handlers
.iter()
.find(|it| which(it).is_ok()) // find the first handler that exists
.ok_or(Error::from_raw_os_error(0)) // If not found, return err
.and_then(|program| {
// If found run the handler
if *program == "gio" {
Command::new(program)
.stdout(Stdio::null())
.stderr(Stdio::null())
.arg("open")
.arg(path.as_ref())
.spawn()?
.wait()
} else {
Command::new(program)
.stdout(Stdio::null())
.stderr(Stdio::null())
.arg(path.as_ref())
.spawn()?
.wait()
}
})
let mut unsuccessful = None;
let mut error = None;

for (command, args) in &open_handlers {
let result = Command::new(command)
.stdout(Stdio::null())
.stderr(Stdio::null())
.args(*args)
.status();

match result {
Ok(status) if status.success() => return result,
Ok(_) => unsuccessful = unsuccessful.or(Some(result)),
Err(err) => error = error.or(Some(Err(err))),
}
}

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

pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result<ExitStatus> {
pub fn with<T: AsRef<OsStr> + Sized>(
path: T,
app: impl Into<String>,
) -> io::Result<ExitStatus> {
Command::new(app.into()).arg(path.as_ref()).spawn()?.wait()
}

// 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),
}
}
}