Skip to content

Commit d09eeae

Browse files
committed
richer set of commands for unix
1 parent 614cacf commit d09eeae

File tree

1 file changed

+67
-33
lines changed

1 file changed

+67
-33
lines changed

src/unix.rs

Lines changed: 67 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{Browser, Error, ErrorKind, Result};
22
use std::os::unix::fs::PermissionsExt;
3-
use std::path::PathBuf;
3+
use std::path::{Path, PathBuf};
44
use std::process::{Command, Stdio};
55

66
macro_rules! try_browser {
@@ -19,44 +19,46 @@ macro_rules! try_browser {
1919
///
2020
/// The mechanism of opening the default browser is as follows:
2121
/// 1. Attempt to use $BROWSER env var if available
22-
/// 2. Attempt to open the url via xdg-open, gvfs-open, gnome-open, open, respectively, whichever works
23-
/// first
22+
/// 2. Attempt to use xdg-open
23+
/// 3. Attempt to use window manager specific commands, like gnome-open, kde-open etc.
24+
/// 4. Fallback to x-www-browser
2425
#[inline]
2526
pub fn open_browser_internal(_: Browser, url: &str) -> Result<()> {
2627
// we first try with the $BROWSER env
2728
try_with_browser_env(url)
2829
// then we try with xdg-open
2930
.or_else(|_| try_browser!("xdg-open", url))
3031
// else do desktop specific stuff
31-
.or_else(|r| {
32-
// detect desktop
33-
let desktop_env: String = std::env::var("XDG_CURRENT_DESKTOP")
34-
.unwrap_or_else(|_| String::from("unknown"))
35-
.to_ascii_uppercase();
36-
match desktop_env.as_str() {
37-
"KDE" => try_browser!("kde-open", url).or_else(|_| try_browser!("kde-open5", url)),
38-
"GNOME" | "CINNAMON" => try_browser!("gio", "open", url)
39-
.or_else(|_| try_browser!("gvfs-open", url))
40-
.or_else(|_| try_browser!("gnome-open", url)),
41-
"MATE" => try_browser!("gio", "open", url)
42-
.or_else(|_| try_browser!("gvfs-open", url))
43-
.or_else(|_| try_browser!("mate-open", url)),
44-
"XFCE" => try_browser!("exo-open", url)
45-
.or_else(|_| try_browser!("gio", "open", url))
46-
.or_else(|_| try_browser!("gvfs-open", url)),
47-
_ => Err(r),
48-
}
32+
.or_else(|r| match guess_desktop_env() {
33+
"kde" => try_browser!("kde-open", url)
34+
.or_else(|_| try_browser!("kde-open5", url))
35+
.or_else(|_| try_browser!("kfmclient", "newTab", url)),
36+
37+
"gnome" => try_browser!("gio", "open", url)
38+
.or_else(|_| try_browser!("gvfs-open", url))
39+
.or_else(|_| try_browser!("gnome-open", url)),
40+
41+
"mate" => try_browser!("gio", "open", url)
42+
.or_else(|_| try_browser!("gvfs-open", url))
43+
.or_else(|_| try_browser!("mate-open", url)),
44+
45+
"xfce" => try_browser!("exo-open", url)
46+
.or_else(|_| try_browser!("gio", "open", url))
47+
.or_else(|_| try_browser!("gvfs-open", url)),
48+
49+
_ => Err(r),
4950
})
5051
// at the end, we'll try x-www-browser and return the result as is
5152
.or_else(|_| try_browser!("x-www-browser", url))
52-
// and convert the result into a () on success
53-
.and_then(|_| Ok(()))
54-
.or_else(|_| {
55-
Err(Error::new(
53+
// if all above failed, map error to not found
54+
.map_err(|_| {
55+
Error::new(
5656
ErrorKind::NotFound,
5757
"No valid browsers detected. You can specify one in BROWSERS environment variable",
58-
))
58+
)
5959
})
60+
// and convert a successful result into a ()
61+
.map(|_| ())
6062
}
6163

6264
#[inline]
@@ -77,14 +79,14 @@ fn try_with_browser_env(url: &str) -> Result<()> {
7779
let browser_cmd = cmdarr[0];
7880
let env_exit = for_matching_path(browser_cmd, |pb| {
7981
let mut cmd = Command::new(pb);
80-
for i in 1..cmdarr.len() {
81-
cmd.arg(cmdarr[i]);
82+
for arg in cmdarr.iter().skip(1) {
83+
cmd.arg(arg);
8284
}
8385
if !browser.contains("%s") {
8486
// append the url as an argument only if it was not already set via %s
8587
cmd.arg(url);
8688
}
87-
run_command(&mut cmd, !is_text_browser(&pb))
89+
run_command(&mut cmd, !is_text_browser(pb))
8890
});
8991
if env_exit.is_ok() {
9092
return Ok(());
@@ -97,9 +99,41 @@ fn try_with_browser_env(url: &str) -> Result<()> {
9799
))
98100
}
99101

102+
/// Detect the desktop environment
103+
#[inline]
104+
fn guess_desktop_env() -> &'static str {
105+
let unknown = "unknown";
106+
let xcd: String = std::env::var("XDG_CURRENT_DESKTOP")
107+
.unwrap_or_else(|_| unknown.into())
108+
.to_ascii_lowercase();
109+
let dsession: String = std::env::var("DESKTOP_SESSION")
110+
.unwrap_or_else(|_| unknown.into())
111+
.to_ascii_lowercase();
112+
113+
if xcd.contains("gnome") || xcd.contains("cinnamon") || dsession.contains("gnome") {
114+
// GNOME and its derivatives
115+
"gnome"
116+
} else if xcd.contains("kde")
117+
|| std::env::var("KDE_FULL_SESSION").is_ok()
118+
|| std::env::var("KDE_SESSION_VERSION").is_ok()
119+
{
120+
// KDE: https://userbase.kde.org/KDE_System_Administration/Environment_Variables#Automatically_Set_Variables
121+
"kde"
122+
} else if xcd.contains("mate") || dsession.contains("mate") {
123+
// We'll treat MATE as distinct from GNOME due to mate-open
124+
"mate"
125+
} else if xcd.contains("xfce") || dsession.contains("xfce") {
126+
// XFCE
127+
"xfce"
128+
} else {
129+
// All others
130+
unknown
131+
}
132+
}
133+
100134
/// Returns true if specified command refers to a known list of text browsers
101135
#[inline]
102-
fn is_text_browser(pb: &PathBuf) -> bool {
136+
fn is_text_browser(pb: &Path) -> bool {
103137
for browser in TEXT_BROWSERS.iter() {
104138
if pb.ends_with(&browser) {
105139
return true;
@@ -129,7 +163,7 @@ where
129163
} else {
130164
// search for this name inside PATH
131165
if let Ok(path) = std::env::var("PATH") {
132-
for entry in path.split(":") {
166+
for entry in path.split(':') {
133167
let mut pb = std::path::PathBuf::from(entry);
134168
pb.push(name);
135169
if let Ok(metadata) = pb.metadata() {
@@ -154,7 +188,7 @@ fn run_command(cmd: &mut Command, background: bool) -> Result<()> {
154188
.stdout(Stdio::null())
155189
.stderr(Stdio::null())
156190
.spawn()
157-
.and_then(|_| Ok(()))
191+
.map(|_| ())
158192
} else {
159193
// if we're in foreground, use status() instead of spawn(), as we'd like to wait
160194
// till completion
@@ -171,6 +205,6 @@ fn run_command(cmd: &mut Command, background: bool) -> Result<()> {
171205
}
172206
}
173207

174-
static TEXT_BROWSERS: [&'static str; 9] = [
208+
static TEXT_BROWSERS: [&str; 9] = [
175209
"lynx", "links", "links2", "elinks", "w3m", "eww", "netrik", "retawq", "curl",
176210
];

0 commit comments

Comments
 (0)