From e83d00653f3926163131e8d91ac5d195bf2c388c Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 22 Jan 2024 14:01:00 -0600 Subject: [PATCH] refactor(shell): Move tree's unicode detection to shell --- src/bin/cargo/commands/tree.rs | 21 +++++------- src/cargo/core/shell.rs | 59 ++++++++++++++++++++++++++++++++++ src/cargo/ops/tree/mod.rs | 22 ++----------- 3 files changed, 69 insertions(+), 33 deletions(-) diff --git a/src/bin/cargo/commands/tree.rs b/src/bin/cargo/commands/tree.rs index 5a9dd23843fd..33bdee42c93b 100644 --- a/src/bin/cargo/commands/tree.rs +++ b/src/bin/cargo/commands/tree.rs @@ -2,12 +2,12 @@ use crate::cli; use crate::command_prelude::*; use anyhow::{bail, format_err}; use cargo::core::dependency::DepKind; +use cargo::core::shell::Charset; use cargo::ops::tree::{self, EdgeKind}; use cargo::ops::Packages; use cargo::util::print_available_packages; use cargo::util::CargoResult; use std::collections::HashSet; -use std::io::IsTerminal as _; use std::str::FromStr; pub fn cli() -> Command { @@ -184,18 +184,14 @@ subtree of the package given to -p.\n\ print_available_packages(&ws)?; } - let charset = args.get_one::("charset"); - let charset = charset - .map(|c| tree::Charset::from_str(c)) + if let Some(charset) = args + .get_one::("charset") + .map(|c| Charset::from_str(c)) .transpose() - .map_err(|e| anyhow::anyhow!("{}", e))?; - let charset = charset.unwrap_or_else(|| { - if supports_unicode::supports_unicode() || !std::io::stdout().is_terminal() { - tree::Charset::Utf8 - } else { - tree::Charset::Ascii - } - }); + .map_err(|e| anyhow::anyhow!("{}", e))? + { + config.shell().set_charset(charset)?; + } let opts = tree::TreeOptions { cli_features: args.cli_features()?, packages, @@ -206,7 +202,6 @@ subtree of the package given to -p.\n\ prefix, no_dedupe, duplicates: args.flag("duplicates"), - charset, format: args.get_one::("format").cloned().unwrap(), graph_features, max_display_depth: args.value_of_u32("depth")?.unwrap_or(u32::MAX), diff --git a/src/cargo/core/shell.rs b/src/cargo/core/shell.rs index 3d446664f3d0..f35fa1483ff9 100644 --- a/src/cargo/core/shell.rs +++ b/src/cargo/core/shell.rs @@ -39,6 +39,34 @@ impl TtyWidth { } } +#[derive(Copy, Clone, Debug)] +pub enum Charset { + Utf8, + Ascii, +} + +impl Charset { + fn auto_with(stream: &dyn IsTerminal) -> Self { + if !stream.is_terminal() || supports_unicode::supports_unicode() { + Self::Utf8 + } else { + Self::Ascii + } + } +} + +impl std::str::FromStr for Charset { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + match s { + "utf8" => Ok(Charset::Utf8), + "ascii" => Ok(Charset::Ascii), + _ => Err("invalid charset"), + } + } +} + /// The requested verbosity of output. #[derive(Debug, Clone, Copy, PartialEq)] pub enum Verbosity { @@ -88,6 +116,8 @@ enum ShellOut { stderr_tty: bool, color_choice: ColorChoice, hyperlinks: bool, + stdout_charset: Charset, + stderr_charset: Charset, }, } @@ -115,6 +145,8 @@ impl Shell { stderr: AutoStream::new(std::io::stderr(), stderr_choice), color_choice: auto_clr, hyperlinks: supports_hyperlinks(), + stdout_charset: Charset::auto_with(&std::io::stdout()), + stderr_charset: Charset::auto_with(&std::io::stderr()), stderr_tty: std::io::stderr().is_terminal(), }, verbosity: Verbosity::Verbose, @@ -330,6 +362,33 @@ impl Shell { Ok(()) } + pub fn set_charset(&mut self, charset: Charset) -> CargoResult<()> { + if let ShellOut::Stream { + ref mut stdout_charset, + ref mut stderr_charset, + .. + } = self.output + { + *stdout_charset = charset; + *stderr_charset = charset; + } + Ok(()) + } + + pub fn out_charset(&self) -> Charset { + match &self.output { + ShellOut::Write(_) => Charset::Utf8, + ShellOut::Stream { stdout_charset, .. } => *stdout_charset, + } + } + + pub fn err_charset(&self) -> Charset { + match &self.output { + ShellOut::Write(_) => Charset::Utf8, + ShellOut::Stream { stderr_charset, .. } => *stderr_charset, + } + } + /// Gets the current color choice. /// /// If we are not using a color stream, this will always return `Never`, even if the color diff --git a/src/cargo/ops/tree/mod.rs b/src/cargo/ops/tree/mod.rs index 79a69a66a4f0..41b01f6dd8da 100644 --- a/src/cargo/ops/tree/mod.rs +++ b/src/cargo/ops/tree/mod.rs @@ -4,6 +4,7 @@ use self::format::Pattern; use crate::core::compiler::{CompileKind, RustcTargetData}; use crate::core::dependency::DepKind; use crate::core::resolver::{features::CliFeatures, ForceAllTargets, HasDevUnits}; +use crate::core::shell::Charset; use crate::core::{Package, PackageId, PackageIdSpec, PackageIdSpecQuery, Workspace}; use crate::ops::{self, Packages}; use crate::util::{CargoResult, Config}; @@ -39,8 +40,6 @@ pub struct TreeOptions { /// appear with different versions, and report if any where found. Implies /// `invert`. pub duplicates: bool, - /// The style of characters to use. - pub charset: Charset, /// A format string indicating how each package should be displayed. pub format: String, /// Includes features in the tree as separate nodes. @@ -68,23 +67,6 @@ impl Target { } } -pub enum Charset { - Utf8, - Ascii, -} - -impl FromStr for Charset { - type Err = &'static str; - - fn from_str(s: &str) -> Result { - match s { - "utf8" => Ok(Charset::Utf8), - "ascii" => Ok(Charset::Ascii), - _ => Err("invalid charset"), - } - } -} - #[derive(Clone, Copy)] pub enum Prefix { None, @@ -238,7 +220,7 @@ fn print( let format = Pattern::new(&opts.format) .with_context(|| format!("tree format `{}` not valid", opts.format))?; - let symbols = match opts.charset { + let symbols = match config.shell().out_charset() { Charset::Utf8 => &UTF8_SYMBOLS, Charset::Ascii => &ASCII_SYMBOLS, };