Skip to main content

acp_cli/output/
text.rs

1use std::io::{self, IsTerminal, Write};
2
3use indicatif::{ProgressBar, ProgressStyle};
4
5use super::OutputRenderer;
6
7pub struct TextRenderer {
8    spinner: Option<ProgressBar>,
9    is_tty: bool,
10}
11
12impl TextRenderer {
13    pub fn new() -> Self {
14        let is_tty = io::stdout().is_terminal();
15        Self {
16            spinner: None,
17            is_tty,
18        }
19    }
20
21    fn clear_spinner(&mut self) {
22        if let Some(spinner) = self.spinner.take() {
23            spinner.finish_and_clear();
24        }
25    }
26
27    fn show_spinner(&mut self, message: &str) {
28        self.clear_spinner();
29        if self.is_tty {
30            let pb = ProgressBar::new_spinner();
31            pb.set_style(
32                ProgressStyle::with_template("{spinner:.cyan} {msg}")
33                    .unwrap()
34                    .tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"),
35            );
36            pb.set_message(message.to_string());
37            pb.enable_steady_tick(std::time::Duration::from_millis(80));
38            self.spinner = Some(pb);
39        } else {
40            eprintln!("{message}");
41        }
42    }
43}
44
45impl Default for TextRenderer {
46    fn default() -> Self {
47        Self::new()
48    }
49}
50
51impl OutputRenderer for TextRenderer {
52    fn text_chunk(&mut self, text: &str) {
53        self.clear_spinner();
54        print!("{text}");
55        let _ = io::stdout().flush();
56    }
57
58    fn tool_status(&mut self, tool: &str) {
59        self.show_spinner(&format!("Using tool: {tool}"));
60    }
61
62    fn permission_denied(&mut self, tool: &str) {
63        self.clear_spinner();
64        eprintln!("Permission denied: {tool}");
65    }
66
67    fn error(&mut self, err: &str) {
68        self.clear_spinner();
69        eprintln!("Error: {err}");
70    }
71
72    fn session_info(&mut self, id: &str) {
73        self.clear_spinner();
74        eprintln!("Session: {id}");
75    }
76
77    fn done(&mut self) {
78        self.clear_spinner();
79        let _ = io::stdout().flush();
80    }
81}