cargo_rail/output.rs
1//! Centralized output control for CLI commands.
2//!
3//! Provides consistent, ergonomic output handling with quiet mode support.
4//!
5//! # Categories
6//!
7//! **Critical** (always shown):
8//! - [`error!`] - Error messages: `error: something went wrong`
9//! - [`warn!`] - Warnings: `warning: deprecated option`
10//! - [`help!`] - Help hints: `help: try --force`
11//!
12//! **Informational** (suppressed with `--quiet`):
13//! - [`status!`] - Progress messages (no prefix)
14//! - [`note!`] - Notes: `note: config found at /path`
15
16use std::sync::atomic::{AtomicBool, Ordering};
17
18// Global State
19
20static QUIET: AtomicBool = AtomicBool::new(false);
21static JSON_MODE: AtomicBool = AtomicBool::new(false);
22
23/// Initialize output settings. Call once at startup.
24#[doc(hidden)]
25pub fn init(quiet: bool) {
26 QUIET.store(quiet, Ordering::Relaxed);
27}
28
29/// Check if quiet mode is enabled.
30pub fn is_quiet() -> bool {
31 QUIET.load(Ordering::Relaxed)
32}
33
34/// Check if JSON mode is enabled.
35pub fn is_json_mode() -> bool {
36 JSON_MODE.load(Ordering::Relaxed)
37}
38
39/// Enable JSON mode (automatically enables quiet mode).
40#[doc(hidden)]
41pub fn set_json_mode(json: bool) {
42 JSON_MODE.store(json, Ordering::Relaxed);
43 if json {
44 QUIET.store(true, Ordering::Relaxed);
45 }
46}
47
48// Critical Output (always shown)
49
50/// Print an error message to stderr.
51///
52/// Always shown, even in quiet mode. Adds `error: ` prefix.
53///
54/// ```ignore
55/// error!("failed to read file");
56/// // Output: error: failed to read file
57/// ```
58#[macro_export]
59macro_rules! error {
60 ($($arg:tt)*) => {
61 eprintln!("error: {}", format_args!($($arg)*))
62 };
63}
64
65/// Print a warning message to stderr.
66///
67/// Always shown, even in quiet mode. Adds `warning: ` prefix.
68///
69/// ```ignore
70/// warn!("deprecated option will be removed in v2.0");
71/// // Output: warning: deprecated option will be removed in v2.0
72/// ```
73#[macro_export]
74macro_rules! warn {
75 ($($arg:tt)*) => {
76 eprintln!("warning: {}", format_args!($($arg)*))
77 };
78}
79
80/// Print a help hint to stderr.
81///
82/// Always shown, even in quiet mode. Adds `help: ` prefix.
83/// Typically used after an error to suggest a fix.
84///
85/// ```ignore
86/// error!("missing required argument");
87/// help!("run with --help for usage");
88/// // Output:
89/// // error: missing required argument
90/// // help: run with --help for usage
91/// ```
92#[macro_export]
93macro_rules! help {
94 ($($arg:tt)*) => {
95 eprintln!("help: {}", format_args!($($arg)*))
96 };
97}
98
99/// Print a status/progress message to stderr.
100///
101/// Suppressed in quiet mode. No prefix added.
102/// Use for transient progress info like "analyzing...", "writing files...".
103///
104/// ```ignore
105/// status!("analyzing {} crates...", crates.len());
106/// // Output: analyzing 42 crates...
107/// ```
108#[macro_export]
109macro_rules! status {
110 ($($arg:tt)*) => {
111 if !$crate::output::is_quiet() {
112 eprintln!($($arg)*)
113 }
114 };
115}
116
117/// Print a note to stderr.
118///
119/// Suppressed in quiet mode. Adds `note: ` prefix.
120/// Use for non-critical informational messages.
121///
122/// ```ignore
123/// note!("existing config found at {}", path.display());
124/// // Output: note: existing config found at /project/.config/rail.toml
125/// ```
126#[macro_export]
127macro_rules! note {
128 ($($arg:tt)*) => {
129 if !$crate::output::is_quiet() {
130 eprintln!("note: {}", format_args!($($arg)*))
131 }
132 };
133}
134
135/// Alias for [`status!`]. Use whichever reads better in context.
136#[macro_export]
137macro_rules! progress {
138 ($($arg:tt)*) => {
139 $crate::status!($($arg)*)
140 };
141}