hyprshell_exec_lib/
run.rs1use core_lib::{TERMINALS, Warn};
2use std::os::unix::prelude::CommandExt;
3use std::path::Path;
4use std::process::{Command, Stdio};
5use std::{env, io, thread};
6use tracing::{debug, error, info, trace};
7
8pub fn run_program(
9 run: &str,
10 path: Option<Box<Path>>,
11 terminal: bool,
12 default_terminal: &Option<Box<str>>,
13) {
14 debug!("Running: {run}");
15 if terminal {
16 if let Some(term) = default_terminal {
17 let command = format!("{term} -e {run}");
18 run_command(&command, &path).warn("Failed to run command");
19 } else {
20 let path_env = env::var_os("PATH").unwrap_or_default();
21 info!(
22 "No default terminal found, searching common terminals in PATH. (Set default_terminal in config to avoid this search)"
23 );
24 trace!("PATH: {}", path_env.to_string_lossy());
25 let paths: Vec<_> = env::split_paths(&path_env).collect();
26 let mut found_terminal = false;
27 for term in TERMINALS {
28 if paths.iter().any(|p| p.join(term).exists()) {
29 let command = format!("{term} -e {run}");
30 if run_command(&command, &path).is_ok() {
31 trace!("Found and launched terminal: {term}");
32 found_terminal = true;
33 break;
34 }
35 }
36 }
37 if !found_terminal {
38 error!("Failed to find a terminal to run the command");
39 }
40 }
41 } else {
42 run_command(run, &path).warn("Failed to run command");
43 }
44}
45
46fn get_command(command: &str) -> Command {
47 if env::var_os("INVOCATION_ID").is_some() {
49 let mut cmd = Command::new("systemd-run");
50 cmd.args(["--user", "--scope", "--collect", "sh", "-c", command]);
51 cmd
52 } else {
53 let mut cmd = Command::new("sh");
54 cmd.args(["-c", command]);
55 cmd
56 }
57}
58
59fn run_command(run: &str, path: &Option<Box<Path>>) -> io::Result<()> {
60 trace!("Original command: {:?}", run);
61 let mut cmd = get_command(run);
62 cmd.process_group(0);
63 if let Some(path) = path {
64 cmd.current_dir(path.as_ref());
65 }
66
67 debug!("Running command: {:?}", cmd);
68 let _out = cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).spawn()?;
69
70 thread::spawn(move || {
71 let output = _out.wait_with_output();
72 if env::var_os("HYPRSHELL_SHOW_OUTPUT").is_some() {
73 if let Ok(output) = output {
74 if !output.stdout.is_empty() || !output.stderr.is_empty() {
75 debug!("Output: {:?}", output);
76 }
77 }
78 }
79 });
80 Ok(())
81}