diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index 959694f75f930..badb1e522993b 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -296,6 +296,24 @@ pub enum ColorChoice { Never, } +impl ColorChoice { + /// Combine self (higher priority) with an [`anstream::ColorChoice`] (lower priority). + /// + /// This method allows prioritizing the user choice, while using the inferred choice for a + /// stream as default. + #[must_use] + pub fn and_colorchoice(self, next: anstream::ColorChoice) -> Self { + match self { + Self::Auto => match next { + anstream::ColorChoice::Auto => Self::Auto, + anstream::ColorChoice::Always | anstream::ColorChoice::AlwaysAnsi => Self::Always, + anstream::ColorChoice::Never => Self::Never, + }, + Self::Always | Self::Never => self, + } + } +} + impl From for anstream::ColorChoice { fn from(value: ColorChoice) -> Self { match value { diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs index a27ce472234cd..9e8db59e057f5 100644 --- a/crates/uv/src/lib.rs +++ b/crates/uv/src/lib.rs @@ -219,6 +219,7 @@ async fn run(mut cli: Cli) -> Result { 2.. => logging::Level::ExtraVerbose, }, duration_layer, + globals.color, )?; // Configure the `Printer`, which controls user-facing output in the CLI. diff --git a/crates/uv/src/logging.rs b/crates/uv/src/logging.rs index f446bb9d15b36..d030af780c14e 100644 --- a/crates/uv/src/logging.rs +++ b/crates/uv/src/logging.rs @@ -1,7 +1,6 @@ use std::fmt; use std::str::FromStr; -use anstream::ColorChoice; use anyhow::Context; use jiff::Timestamp; use owo_colors::OwoColorize; @@ -19,6 +18,8 @@ use tracing_subscriber::util::SubscriberInitExt; use tracing_subscriber::{EnvFilter, Layer, Registry}; use tracing_tree::time::Uptime; use tracing_tree::HierarchicalLayer; + +use uv_cli::ColorChoice; #[cfg(feature = "tracing-durations-export")] use uv_static::EnvVars; @@ -117,6 +118,7 @@ where pub(crate) fn setup_logging( level: Level, durations: impl Layer + Send + Sync, + color: ColorChoice, ) -> anyhow::Result<()> { let default_directive = match level { Level::Default => { @@ -140,6 +142,11 @@ pub(crate) fn setup_logging( .from_env() .context("Invalid RUST_LOG directives")?; + let ansi = match color.and_colorchoice(anstream::Stderr::choice(&std::io::stderr())) { + ColorChoice::Always => true, + ColorChoice::Never => false, + ColorChoice::Auto => unreachable!("anstream can't return auto as choice"), + }; match level { Level::Default | Level::Verbose => { // Regardless of the tracing level, show messages without any adornment. @@ -148,12 +155,7 @@ pub(crate) fn setup_logging( display_level: true, show_spans: false, }; - let ansi = match anstream::Stderr::choice(&std::io::stderr()) { - ColorChoice::Always | ColorChoice::AlwaysAnsi => true, - ColorChoice::Never => false, - // We just asked anstream for a choice, that can't be auto - ColorChoice::Auto => unreachable!(), - }; + tracing_subscriber::registry() .with(durations_layer) .with( @@ -174,6 +176,7 @@ pub(crate) fn setup_logging( .with_targets(true) .with_timer(Uptime::default()) .with_writer(std::io::stderr) + .with_ansi(ansi) .with_filter(filter), ) .init();