Skip to main content

taba_cli/
system.rs

1//! The real platform: environment, terminal, network and processes of the system.
2
3use std::io::{self, IsTerminal, Write};
4use std::process::{Command, Stdio};
5
6use taba_client::{Client, Config, Error as ApiError};
7
8use crate::app::Platform;
9use crate::profile::Os;
10use crate::tui::{term::RawTerminal, Terminal};
11
12pub struct RealPlatform;
13
14impl Platform for RealPlatform {
15    fn env(&self, name: &str) -> Option<String> {
16        std::env::var(name).ok()
17    }
18
19    fn os(&self) -> Os {
20        Os::current()
21    }
22
23    fn stdin_is_tty(&self) -> bool {
24        io::stdin().is_terminal()
25    }
26
27    fn stdout_is_tty(&self) -> bool {
28        io::stdout().is_terminal()
29    }
30
31    fn client(&self, config: Config) -> Result<Client, ApiError> {
32        Client::new(config)
33    }
34
35    fn exec(&self, command: &str, stdin: &[u8]) -> io::Result<i32> {
36        let mut shell = if cfg!(windows) {
37            let mut c = Command::new("cmd");
38            c.args(["/C", command]);
39            c
40        } else {
41            let mut c = Command::new("sh");
42            c.args(["-c", command]);
43            c
44        };
45        let mut child = shell.stdin(Stdio::piped()).spawn()?;
46        if let Some(mut pipe) = child.stdin.take() {
47            // The command may exit without reading everything; a broken pipe here is not an error.
48            let _ = pipe.write_all(stdin);
49        }
50        Ok(child.wait()?.code().unwrap_or(-1))
51    }
52
53    fn terminal(&self) -> Option<Box<dyn Terminal>> {
54        RawTerminal::open()
55            .ok()
56            .map(|t| Box::new(t) as Box<dyn Terminal>)
57    }
58}