Skip to main content

opal/
terminal.rs

1use anyhow::Result;
2use std::env;
3use std::io::{self, BufRead, IsTerminal, Read};
4use std::sync::mpsc::{self, Sender};
5use std::thread;
6
7pub fn should_use_color() -> bool {
8    if env::var_os("NO_COLOR").is_some() {
9        return false;
10    }
11
12    if env::var_os("CLICOLOR_FORCE").is_some_and(|v| v != "0") {
13        return true;
14    }
15
16    match env::var("OPAL_COLOR") {
17        Ok(val) if matches!(val.as_str(), "always" | "1" | "true") => return true,
18        Ok(val) if matches!(val.as_str(), "never" | "0" | "false") => return false,
19        _ => {}
20    }
21
22    if !io::stdout().is_terminal() {
23        return false;
24    }
25
26    true
27}
28
29pub fn stream_lines<F>(
30    stdout: impl Read + Send + 'static,
31    stderr: impl Read + Send + 'static,
32    mut on_line: F,
33) -> Result<()>
34where
35    F: FnMut(String) -> Result<()>,
36{
37    let (tx, rx) = mpsc::channel::<Result<String, io::Error>>();
38    spawn_reader(stdout, tx.clone());
39    spawn_reader(stderr, tx.clone());
40    drop(tx);
41
42    for line in rx {
43        let line = line?;
44        on_line(line)?;
45    }
46
47    Ok(())
48}
49
50fn spawn_reader<R>(reader: R, tx: Sender<Result<String, io::Error>>)
51where
52    R: Read + Send + 'static,
53{
54    thread::spawn(move || {
55        let mut reader = io::BufReader::new(reader);
56        loop {
57            let mut buf = String::new();
58            match reader.read_line(&mut buf) {
59                Ok(0) => break,
60                Ok(_) => {
61                    if buf.ends_with('\n') {
62                        buf.pop();
63                        if buf.ends_with('\r') {
64                            buf.pop();
65                        }
66                    }
67                    if tx.send(Ok(buf)).is_err() {
68                        break;
69                    }
70                }
71                Err(err) => {
72                    let _ = tx.send(Err(err));
73                    break;
74                }
75            }
76        }
77    });
78}