1use crate::{DetectionError, Terminal};
6use configparser::ini::Ini;
7use std::{env::var, path::Path, process::Command};
8
9trait SpawnCleanStringify {
11 fn spawn_clean_stringify(&mut self) -> Result<String, DetectionError>;
12}
13
14impl SpawnCleanStringify for Command {
15 fn spawn_clean_stringify(&mut self) -> Result<String, DetectionError> {
16 let child = self.stdout(std::process::Stdio::piped()).spawn()?;
17 let output = child.wait_with_output()?;
18 Ok(String::from_utf8(output.stdout)
19 .unwrap_or_default()
20 .trim()
21 .to_owned())
22 }
23}
24
25fn get_home() -> String {
26 var("HOME").unwrap_or_default()
27}
28
29fn gsettings_desktop_get(desktop_name: &str) -> Result<Terminal, DetectionError> {
31 let mut maybe_term = Command::new("gsettings")
32 .arg("get")
33 .arg(format!(
34 "{}.desktop.default-applications.terminal",
35 desktop_name
36 ))
37 .arg("exec")
38 .spawn_clean_stringify()?;
39 if maybe_term.starts_with('\'') && maybe_term.ends_with('\'') && maybe_term.len() > 1 {
40 maybe_term = maybe_term[1..maybe_term.len() - 1].to_owned();
41 }
42 if maybe_term.is_empty() {
43 Err(DetectionError::DEFindError)
44 } else {
45 Ok(maybe_term.into())
46 }
47}
48
49fn ini_get<P: AsRef<Path>>(
51 path: P,
52 section: &str,
53 key: &str,
54) -> Result<Option<String>, DetectionError> {
55 let mut config = Ini::new_cs();
56 if let Err(e) = config.load(path) {
57 return Err(DetectionError::IniParseError(e));
58 };
59 Ok(config.get(section, key))
60}
61
62pub fn detect_terminal_desktop_cinnamon() -> Result<Terminal, DetectionError> {
66 gsettings_desktop_get("org.cinnamon")
67}
68
69pub fn detect_terminal_desktop_deepin() -> Result<Terminal, DetectionError> {
73 gsettings_desktop_get("org.deepin")
74}
75
76pub fn detect_terminal_desktop_gnome() -> Result<Terminal, DetectionError> {
84 gsettings_desktop_get("org.gnome")
85}
86
87pub fn detect_terminal_desktop_kde() -> Result<Terminal, DetectionError> {
93 let maybe_term = Command::new("kreadconfig5")
94 .arg("--group")
95 .arg("General")
96 .arg("--key")
97 .arg("TerminalApplication")
98 .spawn_clean_stringify()?;
99 Ok(if maybe_term.is_empty() {
100 "konsole".into()
101 } else {
102 maybe_term.into()
103 })
104}
105
106pub fn detect_terminal_desktop_lxde() -> Result<Terminal, DetectionError> {
112 let filename = format!(
113 "{}/.config/lxsession/{}/desktop.conf",
114 get_home(),
115 var("XDG_SESSION_DESKTOP").unwrap_or("LXDE".to_owned()),
116 );
117 let Some(term) = ini_get(filename, "Session", "terminal_manager/command")? else {
118 return Err(DetectionError::DEFindError);
119 };
120 Ok(term.into())
121}
122
123pub fn detect_terminal_desktop_lxqt() -> Result<Terminal, DetectionError> {
130 if let Ok(term) = var("LXQT_TERMINAL_EMULATOR") {
131 return Ok(term.into());
132 }
133 let filename = format!("{}/.config/lxqt/session.conf", get_home());
134 let Some(term) = ini_get(filename, "Environment", "TERM")? else {
135 return Err(DetectionError::DEFindError);
136 };
137 Ok(term.into())
138}
139
140pub fn detect_terminal_desktop_xfce() -> Result<Terminal, DetectionError> {
144 let filename = format!("{}/.config/xfce4/helpers.rc", get_home());
145 Ok(ini_get(filename, "default", "TerminalEmulator")?
146 .unwrap_or("xfce4-terminal".to_owned())
147 .into())
148}