Skip to main content

bn/
output.rs

1/// Thin output abstraction for consistent CLI messaging.
2///
3/// All human-readable messages go to stderr, keeping stdout clean for
4/// machine-readable output (JSON, piped IDs). Supports quiet mode
5/// to suppress informational messages while preserving warnings and errors.
6pub struct Output {
7    quiet: bool,
8}
9
10impl Output {
11    /// Create a new Output with default settings (not quiet).
12    pub fn new() -> Self {
13        Self { quiet: false }
14    }
15
16    /// Create an Output from a quiet flag.
17    pub fn with_quiet(quiet: bool) -> Self {
18        Self { quiet }
19    }
20
21    /// Informational message. Suppressed in quiet mode.
22    pub fn info(&self, msg: &str) {
23        if !self.quiet {
24            eprintln!("{}", msg);
25        }
26    }
27
28    /// Success message with a bean ID prefix. Suppressed in quiet mode.
29    pub fn success(&self, id: &str, msg: &str) {
30        if !self.quiet {
31            eprintln!("  ✓ {}  {}", id, msg);
32        }
33    }
34
35    /// Warning message. Never suppressed.
36    pub fn warn(&self, msg: &str) {
37        eprintln!("  ⚠ {}", msg);
38    }
39
40    /// Error message. Never suppressed.
41    pub fn error(&self, msg: &str) {
42        eprintln!("  ✗ {}", msg);
43    }
44}
45
46impl Default for Output {
47    fn default() -> Self {
48        Self::new()
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn output_new_is_not_quiet() {
58        let out = Output::new();
59        assert!(!out.quiet);
60    }
61
62    #[test]
63    fn output_default_is_not_quiet() {
64        let out = Output::default();
65        assert!(!out.quiet);
66    }
67
68    #[test]
69    fn output_with_quiet_true() {
70        let out = Output::with_quiet(true);
71        assert!(out.quiet);
72    }
73
74    #[test]
75    fn output_with_quiet_false() {
76        let out = Output::with_quiet(false);
77        assert!(!out.quiet);
78    }
79}