diff --git a/src/cargo/core/shell.rs b/src/cargo/core/shell.rs index f35fa1483ff9..1e75174dbe38 100644 --- a/src/cargo/core/shell.rs +++ b/src/cargo/core/shell.rs @@ -9,6 +9,8 @@ use crate::util::errors::CargoResult; use crate::util::hostname; use crate::util::style::*; +pub use crate::util::config::Charset; + pub enum TtyWidth { NoTty, Known(usize), @@ -39,34 +41,6 @@ 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 { diff --git a/src/cargo/util/config/mod.rs b/src/cargo/util/config/mod.rs index 0e161ba8af4e..07bc84663448 100644 --- a/src/cargo/util/config/mod.rs +++ b/src/cargo/util/config/mod.rs @@ -1055,6 +1055,9 @@ impl Config { if let Some(hyperlinks) = term.hyperlinks { self.shell().set_hyperlinks(hyperlinks)?; } + if let Some(charset) = term.charset { + self.shell().set_charset(charset)?; + } self.progress_config = term.progress.unwrap_or_default(); self.extra_verbose = extra_verbose; self.frozen = frozen; @@ -2605,11 +2608,53 @@ struct TermConfig { quiet: Option, color: Option, hyperlinks: Option, + charset: Option, #[serde(default)] #[serde(deserialize_with = "progress_or_string")] progress: Option, } +#[derive(Copy, Clone, Debug)] +pub enum Charset { + Utf8, + Ascii, +} + +impl Charset { + pub fn auto_with(stream: &dyn std::io::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"), + } + } +} + +impl<'de> Deserialize<'de> for Charset { + fn deserialize(d: D) -> Result + where + D: serde::de::Deserializer<'de>, + { + use serde::de::Error as _; + UntaggedEnumVisitor::new() + .expecting("a charset") + .string(|value| value.parse().map_err(serde_untagged::de::Error::custom)) + .deserialize(d) + } +} + #[derive(Debug, Default, Deserialize)] pub struct ProgressConfig { pub when: ProgressWhen, diff --git a/src/doc/src/reference/config.md b/src/doc/src/reference/config.md index 25e17ac907f6..c34135c8cb4a 100644 --- a/src/doc/src/reference/config.md +++ b/src/doc/src/reference/config.md @@ -181,6 +181,7 @@ quiet = false # whether cargo output is quiet verbose = false # whether cargo provides verbose output color = 'auto' # whether cargo colorizes output hyperlinks = true # whether cargo inserts links into output +charset = "utf8" # what cargo is limited to in rendering output progress.when = 'auto' # whether cargo shows progress bar progress.width = 80 # width of progress bar ``` @@ -1279,6 +1280,16 @@ Can be overridden with the `--color` command-line option. Controls whether or not hyperlinks are used in the terminal. +#### `term.charset` +* Type: string +* Default: auto-detect +* Environment: `CARGO_TERM_CHARSET` + +Sets what characters can be used when rendering cargo output. Possible values: + +* `utf8`: Use the full set of UTF-8 characters for drawing +* `ascii`: Only use 7-bit ASCII characters for drawing + #### `term.progress.when` * Type: string * Default: "auto" diff --git a/tests/testsuite/tree.rs b/tests/testsuite/tree.rs index 16cc37f7e56c..9abf792b561d 100644 --- a/tests/testsuite/tree.rs +++ b/tests/testsuite/tree.rs @@ -1139,7 +1139,7 @@ dupe-dep v2.0.0 } #[cargo_test] -fn charset() { +fn charset_cli() { let p = make_simple_proj(); p.cargo("tree --charset ascii") .with_stdout( @@ -1160,6 +1160,52 @@ foo v0.1.0 ([..]/foo) .run(); } +#[cargo_test] +fn charset_config() { + let p = make_simple_proj(); + p.cargo("tree") + .env("CARGO_TERM_CHARSET", "ascii") + .with_stdout( + "\ +foo v0.1.0 ([..]/foo) +|-- a v1.0.0 +| `-- b v1.0.0 +| `-- c v1.0.0 +`-- c v1.0.0 +[build-dependencies] +`-- bdep v1.0.0 + `-- b v1.0.0 (*) +[dev-dependencies] +`-- devdep v1.0.0 + `-- b v1.0.0 (*) +", + ) + .run(); +} + +#[cargo_test] +fn charset_cli_preferred_over_config() { + let p = make_simple_proj(); + p.cargo("tree --charset ascii") + .env("CARGO_TERM_CHARSET", "unicode") + .with_stdout( + "\ +foo v0.1.0 ([..]/foo) +|-- a v1.0.0 +| `-- b v1.0.0 +| `-- c v1.0.0 +`-- c v1.0.0 +[build-dependencies] +`-- bdep v1.0.0 + `-- b v1.0.0 (*) +[dev-dependencies] +`-- devdep v1.0.0 + `-- b v1.0.0 (*) +", + ) + .run(); +} + #[cargo_test] fn format() { Package::new("dep", "1.0.0").publish();