oxigaf_cli/verbosity.rs
1//! Verbosity level configuration for CLI output.
2//!
3//! Controls logging, progress bars, and timing information based on
4//! command-line flags (-v, -vv, -vvv, -q).
5
6use tracing::Level;
7
8/// Verbosity levels for CLI output.
9///
10/// Determines logging detail, progress bar visibility, and timing information.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
12pub enum Verbosity {
13 /// Only errors (-q).
14 ///
15 /// Suppresses all output except errors. No progress bars or informational messages.
16 Quiet,
17
18 /// Progress + results (default).
19 ///
20 /// Shows progress bars, informational messages, and results.
21 Normal,
22
23 /// Debug info (-v).
24 ///
25 /// Includes timing information and debug-level logging.
26 Verbose,
27
28 /// Trace-level logging (-vv).
29 ///
30 /// Enables trace-level logging with file and line information.
31 Debug,
32
33 /// All internal details (-vvv).
34 ///
35 /// Maximum verbosity with all internal details and trace logging.
36 Trace,
37}
38
39impl Verbosity {
40 /// Create verbosity level from command-line flags.
41 ///
42 /// # Arguments
43 ///
44 /// * `verbose` - Number of `-v` flags (0 = normal, 1 = verbose, 2 = debug, 3+ = trace)
45 /// * `quiet` - Whether `-q` flag was specified (overrides verbose)
46 ///
47 /// # Examples
48 ///
49 /// ```
50 /// use oxigaf_cli::verbosity::Verbosity;
51 ///
52 /// let quiet = Verbosity::from_flags(0, true);
53 /// assert_eq!(quiet, Verbosity::Quiet);
54 ///
55 /// let normal = Verbosity::from_flags(0, false);
56 /// assert_eq!(normal, Verbosity::Normal);
57 ///
58 /// let verbose = Verbosity::from_flags(1, false);
59 /// assert_eq!(verbose, Verbosity::Verbose);
60 ///
61 /// let trace = Verbosity::from_flags(3, false);
62 /// assert_eq!(trace, Verbosity::Trace);
63 /// ```
64 #[must_use]
65 pub fn from_flags(verbose: u8, quiet: bool) -> Self {
66 if quiet {
67 Self::Quiet
68 } else {
69 match verbose {
70 0 => Self::Normal,
71 1 => Self::Verbose,
72 2 => Self::Debug,
73 _ => Self::Trace,
74 }
75 }
76 }
77
78 /// Get the tracing level for this verbosity.
79 ///
80 /// Maps verbosity to appropriate `tracing::Level`:
81 /// - Quiet → ERROR
82 /// - Normal → INFO
83 /// - Verbose → DEBUG
84 /// - Debug/Trace → TRACE
85 #[must_use]
86 pub fn tracing_level(&self) -> Level {
87 match self {
88 Self::Quiet => Level::ERROR,
89 Self::Normal => Level::INFO,
90 Self::Verbose => Level::DEBUG,
91 Self::Debug | Self::Trace => Level::TRACE,
92 }
93 }
94
95 /// Whether progress bars should be shown.
96 ///
97 /// Progress bars are shown in Normal and Verbose modes, but hidden
98 /// in Quiet, Debug, and Trace modes (where detailed logging is preferred).
99 #[must_use]
100 pub fn show_progress(&self) -> bool {
101 matches!(self, Self::Normal | Self::Verbose)
102 }
103
104 /// Whether detailed timing information should be shown.
105 ///
106 /// Timing information is shown in Verbose, Debug, and Trace modes.
107 #[must_use]
108 pub fn show_timing(&self) -> bool {
109 *self >= Self::Verbose
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn test_from_flags_quiet() {
119 let v = Verbosity::from_flags(0, true);
120 assert_eq!(v, Verbosity::Quiet);
121
122 // Quiet overrides verbose flag
123 let v = Verbosity::from_flags(3, true);
124 assert_eq!(v, Verbosity::Quiet);
125 }
126
127 #[test]
128 fn test_from_flags_normal() {
129 let v = Verbosity::from_flags(0, false);
130 assert_eq!(v, Verbosity::Normal);
131 }
132
133 #[test]
134 fn test_from_flags_verbose_levels() {
135 let v1 = Verbosity::from_flags(1, false);
136 assert_eq!(v1, Verbosity::Verbose);
137
138 let v2 = Verbosity::from_flags(2, false);
139 assert_eq!(v2, Verbosity::Debug);
140
141 let v3 = Verbosity::from_flags(3, false);
142 assert_eq!(v3, Verbosity::Trace);
143
144 let v4 = Verbosity::from_flags(10, false);
145 assert_eq!(v4, Verbosity::Trace);
146 }
147
148 #[test]
149 fn test_tracing_level() {
150 assert_eq!(Verbosity::Quiet.tracing_level(), Level::ERROR);
151 assert_eq!(Verbosity::Normal.tracing_level(), Level::INFO);
152 assert_eq!(Verbosity::Verbose.tracing_level(), Level::DEBUG);
153 assert_eq!(Verbosity::Debug.tracing_level(), Level::TRACE);
154 assert_eq!(Verbosity::Trace.tracing_level(), Level::TRACE);
155 }
156
157 #[test]
158 fn test_show_progress() {
159 assert!(!Verbosity::Quiet.show_progress());
160 assert!(Verbosity::Normal.show_progress());
161 assert!(Verbosity::Verbose.show_progress());
162 assert!(!Verbosity::Debug.show_progress());
163 assert!(!Verbosity::Trace.show_progress());
164 }
165
166 #[test]
167 fn test_show_timing() {
168 assert!(!Verbosity::Quiet.show_timing());
169 assert!(!Verbosity::Normal.show_timing());
170 assert!(Verbosity::Verbose.show_timing());
171 assert!(Verbosity::Debug.show_timing());
172 assert!(Verbosity::Trace.show_timing());
173 }
174
175 #[test]
176 fn test_ordering() {
177 assert!(Verbosity::Quiet < Verbosity::Normal);
178 assert!(Verbosity::Normal < Verbosity::Verbose);
179 assert!(Verbosity::Verbose < Verbosity::Debug);
180 assert!(Verbosity::Debug < Verbosity::Trace);
181 }
182}