1use crate::OpenError;
2use std::ffi::OsStr;
3use std::io;
4use std::io::Write;
5use std::process::{Child, Command, Stdio};
6
7const XDG_OPEN_SCRIPT: &[u8] = include_bytes!("xdg-open");
8
9pub(crate) fn open(path: &OsStr) -> Result<(), OpenError> {
10 if crate::is_wsl() {
11 wsl_open(path)
12 } else {
13 non_wsl_open(path)
14 }
15}
16
17#[cfg(all(feature = "reveal", target_os = "linux"))]
18pub(crate) fn reveal(path: &std::path::Path) -> Result<(), OpenError> {
19 if crate::is_wsl() {
20 reveal_in_windows_explorer(path)
21 } else {
22 crate::freedesktop::reveal_with_dbus(path).or_else(|_| reveal_fallback(path))
23 }
24}
25
26#[cfg(all(feature = "reveal", not(target_os = "linux")))]
27pub(crate) fn reveal(path: &std::path::Path) -> Result<(), OpenError> {
28 reveal_fallback(path)
29}
30
31#[cfg(feature = "reveal")]
32fn reveal_fallback(path: &std::path::Path) -> Result<(), OpenError> {
33 let path = path.canonicalize().map_err(OpenError::Io)?;
34 let parent = path.parent().unwrap_or(std::path::Path::new("/"));
35 open(parent.as_os_str())
36}
37
38fn wsl_open(path: &OsStr) -> Result<(), OpenError> {
39 let result: Result = open_with_wslview(path);
40 if let Ok(mut child: Child) = result {
41 return crate::wait_child(&mut child, cmd_name:"wslview");
42 }
43
44 open_with_system_xdg_open(path).map_err(|err: Error| OpenError::Spawn {
45 cmds: "wslview, xdg-open".into(),
46 source: err,
47 })?;
48
49 Ok(())
50}
51
52fn non_wsl_open(path: &OsStr) -> Result<(), OpenError> {
53 if open_with_system_xdg_open(path).is_err() {
54 open_with_internal_xdg_open(path)?;
55 }
56
57 Ok(())
58}
59
60fn open_with_wslview(path: &OsStr) -> io::Result<Child> {
61 Command&mut Command::new("wslview")
62 .arg(path)
63 .stdin(Stdio::null())
64 .stdout(Stdio::null())
65 .stderr(cfg:Stdio::piped())
66 .spawn()
67}
68
69fn open_with_system_xdg_open(path: &OsStr) -> io::Result<Child> {
70 Command&mut Command::new("xdg-open")
71 .arg(path)
72 .stdin(Stdio::null())
73 .stdout(Stdio::null())
74 .stderr(cfg:Stdio::null())
75 .spawn()
76}
77
78fn open_with_internal_xdg_open(path: &OsStr) -> Result<Child, OpenError> {
79 let mut sh: Child = Command::new("sh")
80 .arg("-s")
81 .arg(path)
82 .stdin(Stdio::piped())
83 .stdout(Stdio::null())
84 .stderr(Stdio::null())
85 .spawn()
86 .map_err(|err: Error| OpenError::Spawn {
87 cmds: "sh".into(),
88 source: err,
89 })?;
90
91 sh.stdin
92 .as_mut()
93 .unwrap()
94 .write_all(XDG_OPEN_SCRIPT)
95 .map_err(op:OpenError::Io)?;
96
97 Ok(sh)
98}
99
100#[cfg(all(feature = "reveal", target_os = "linux"))]
101fn reveal_in_windows_explorer(path: &std::path::Path) -> Result<(), OpenError> {
102 let converted_path = crate::wsl_to_windows_path(path.as_os_str());
103 let converted_path = converted_path.as_deref();
104 let path = match converted_path {
105 None => path,
106 Some(x) => std::path::Path::new(x),
107 };
108 Command::new("explorer.exe")
109 .arg("/select,")
110 .arg(path)
111 .stdout(Stdio::null())
112 .stderr(Stdio::null())
113 .spawn()
114 .map_err(|err| OpenError::Spawn {
115 cmds: "explorer.exe".into(),
116 source: err,
117 })?;
118 Ok(())
119}
120
121#[cfg(target_os = "linux")]
122pub(crate) fn is_wsl() -> bool {
123 if is_docker() {
124 return false;
125 }
126
127 if let Ok(true) = std::fs::read_to_string("/proc/sys/kernel/osrelease")
128 .map(|osrelease: String| osrelease.to_ascii_lowercase().contains("microsoft"))
129 {
130 return true;
131 }
132
133 if let Ok(true) = std::fs::read_to_string("/proc/version")
134 .map(|version: String| version.to_ascii_lowercase().contains("microsoft"))
135 {
136 return true;
137 }
138
139 false
140}
141
142#[cfg(target_os = "linux")]
143fn is_docker() -> bool {
144 let has_docker_env: bool = std::fs::metadata(path:"/.dockerenv").is_ok();
145
146 let has_docker_cgroup: bool = std::fs::read_to_string("/proc/self/cgroup")
147 .map(|cgroup| cgroup.to_ascii_lowercase().contains("docker"))
148 .unwrap_or(default:false);
149
150 has_docker_env || has_docker_cgroup
151}
152