1use std::error::Error;
2use std::fmt;
3use std::sync::atomic::AtomicBool;
4use std::sync::{LazyLock, Mutex};
5
6#[doc(hidden)]
8pub use anstream;
9#[doc(hidden)]
10pub use owo_colors;
11use rustc_hash::FxHashSet;
12use uv_errors::{ErrorOptions, Hints, write_error_chain_with_options};
13
14pub static ENABLED: AtomicBool = AtomicBool::new(false);
16
17pub fn enable() {
19 ENABLED.store(true, std::sync::atomic::Ordering::Relaxed);
20}
21
22pub fn disable() {
24 ENABLED.store(false, std::sync::atomic::Ordering::Relaxed);
25}
26
27pub fn write_warning_chain(err: &dyn Error, hints: Hints<'_>) -> fmt::Result {
29 write_warning_chain_with_options(err, hints, ErrorOptions::default())
30}
31
32fn write_warning_chain_with_options<C, W: fmt::Write>(
33 err: &dyn Error,
34 hints: Hints<'_>,
35 options: ErrorOptions<'_, C, W>,
36) -> fmt::Result {
37 write_error_chain_with_options(
38 err,
39 hints,
40 options
41 .with_level("warning")
42 .with_color(owo_colors::AnsiColors::Yellow),
43 )
44}
45
46#[macro_export]
48macro_rules! warn_user {
49 ($($arg:tt)*) => {{
50 use $crate::anstream::eprintln;
51 use $crate::owo_colors::OwoColorize;
52
53 if $crate::ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
54 let message = format!("{}", format_args!($($arg)*));
55 let formatted = message.bold();
56 eprintln!("{}{} {formatted}", "warning".yellow().bold(), ":".bold());
57 }
58 }};
59}
60
61pub static WARNINGS: LazyLock<Mutex<FxHashSet<String>>> = LazyLock::new(Mutex::default);
62
63#[macro_export]
66macro_rules! warn_user_once {
67 ($($arg:tt)*) => {{
68 use $crate::anstream::eprintln;
69 use $crate::owo_colors::OwoColorize;
70
71 if $crate::ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
72 if let Ok(mut states) = $crate::WARNINGS.lock() {
73 let message = format!("{}", format_args!($($arg)*));
74 if states.insert(message.clone()) {
75 eprintln!("{}{} {}", "warning".yellow().bold(), ":".bold(), message.bold());
76 }
77 }
78 }
79 }};
80}
81
82#[cfg(test)]
83mod tests {
84 use anyhow::anyhow;
85 use insta::assert_snapshot;
86 use uv_errors::{ErrorOptions, Hints};
87
88 use super::write_warning_chain_with_options;
89
90 #[test]
91 fn format_warning_chain() {
92 let error = anyhow!("Failed to create registry entry");
93 let mut output = String::new();
94 write_warning_chain_with_options(
95 error.as_ref(),
96 Hints::none(),
97 ErrorOptions::default().with_stream(&mut output),
98 )
99 .unwrap();
100 assert_snapshot!(format!("{output:?}"), @r#""\u{1b}[1m\u{1b}[33mwarning\u{1b}[39m\u{1b}[0m\u{1b}[1m:\u{1b}[0m Failed to create registry entry\n""#);
101 let output = anstream::adapter::strip_str(&output);
102
103 assert_snapshot!(output, @"warning: Failed to create registry entry
104");
105 }
106}