1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
use crate::{get_terminal, DetectionError, Terminal};
use std::ffi::OsStr;
use std::process::Command;

#[cfg(target_os = "linux")]
fn rawstrcmd(cmd: &Command) -> String {
    format!("{:?}", cmd)
}

#[cfg(target_os = "linux")]
fn strcmd(cmd: &Command) -> String {
    format!("bash -c {:?}", rawstrcmd(cmd))
}

/// Allows a `Command` to be executed in a terminal
pub trait InTerminal {
    fn in_terminal(&self, term: Terminal) -> Self;
    fn in_terminal_args<I, S>(&self, term: Terminal, args: I) -> Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>;
}

impl InTerminal for Command {
    fn in_terminal(&self, term: Terminal) -> Self {
        let mut cmd = Command::new(term);
        cmd.arg("-e").arg(strcmd(self));
        cmd
    }
    fn in_terminal_args<I, S>(&self, term: Terminal, args: I) -> Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        let mut cmd = Command::new(term);
        cmd.args(args).arg("-e").arg(strcmd(self));
        cmd
    }
}

/// Allows a `Command` to be executed in a terminal.  
/// Works the same as the non-auto version, but detects the terminal
/// automatically
pub trait InTerminalAuto: InTerminal
where
    Self: Sized,
{
    fn in_terminal(&self) -> Result<Self, DetectionError>;
    fn in_terminal_args<I, S>(&self, args: I) -> Result<Self, DetectionError>
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>;
}

impl InTerminalAuto for Command {
    fn in_terminal(&self) -> Result<Self, DetectionError> {
        Ok(InTerminal::in_terminal(self, get_terminal()?))
    }
    fn in_terminal_args<I, S>(&self, args: I) -> Result<Self, DetectionError>
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        Ok(InTerminal::in_terminal_args(self, get_terminal()?, args))
    }
}