refactor(shell): Switch termcolor to anstream

This commit is contained in:
Ed Page 2023-09-28 16:50:29 -05:00
parent 796398563a
commit b3353c8772
3 changed files with 51 additions and 139 deletions

32
Cargo.lock generated
View file

@ -61,16 +61,6 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "anstyle-termcolor"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11c3d1411f1f4c8a7b177caec3c71b51290f9e8ad9f99124fd3fe9aa96e56834"
dependencies = [
"anstyle",
"termcolor",
]
[[package]] [[package]]
name = "anstyle-wincon" name = "anstyle-wincon"
version = "3.0.1" version = "3.0.1"
@ -248,7 +238,6 @@ version = "0.75.0"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
"anstyle-termcolor",
"anyhow", "anyhow",
"base64", "base64",
"bytesize", "bytesize",
@ -267,7 +256,6 @@ dependencies = [
"curl-sys", "curl-sys",
"filetime", "filetime",
"flate2", "flate2",
"fwdansi",
"git2", "git2",
"git2-curl", "git2-curl",
"gix", "gix",
@ -308,7 +296,6 @@ dependencies = [
"syn 2.0.29", "syn 2.0.29",
"tar", "tar",
"tempfile", "tempfile",
"termcolor",
"time", "time",
"toml", "toml",
"toml_edit", "toml_edit",
@ -993,16 +980,6 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "fwdansi"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08c1f5787fe85505d1f7777268db5103d80a7a374d2316a7ce262e57baf8f208"
dependencies = [
"memchr",
"termcolor",
]
[[package]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.14.7" version = "0.14.7"
@ -3181,15 +3158,6 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "termcolor"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
dependencies = [
"winapi-util",
]
[[package]] [[package]]
name = "terminal_size" name = "terminal_size"
version = "0.3.0" version = "0.3.0"

View file

@ -18,7 +18,6 @@ license = "MIT OR Apache-2.0"
[workspace.dependencies] [workspace.dependencies]
anstream = "0.6.3" anstream = "0.6.3"
anstyle = "1.0.4" anstyle = "1.0.4"
anstyle-termcolor = "1.1.0"
anyhow = "1.0.75" anyhow = "1.0.75"
base64 = "0.21.3" base64 = "0.21.3"
bytesize = "1.3" bytesize = "1.3"
@ -41,7 +40,6 @@ curl = "0.4.44"
curl-sys = "0.4.66" curl-sys = "0.4.66"
filetime = "0.2.22" filetime = "0.2.22"
flate2 = { version = "1.0.27", default-features = false, features = ["zlib"] } flate2 = { version = "1.0.27", default-features = false, features = ["zlib"] }
fwdansi = "1.1.0"
git2 = "0.18.0" git2 = "0.18.0"
git2-curl = "0.19.0" git2-curl = "0.19.0"
gix = { version = "0.54.1", default-features = false, features = ["blocking-http-transport-curl", "progress-tree", "revision"] } gix = { version = "0.54.1", default-features = false, features = ["blocking-http-transport-curl", "progress-tree", "revision"] }
@ -91,7 +89,6 @@ snapbox = { version = "0.4.13", features = ["diff", "path"] }
syn = { version = "2.0.29", features = ["extra-traits", "full"] } syn = { version = "2.0.29", features = ["extra-traits", "full"] }
tar = { version = "0.4.40", default-features = false } tar = { version = "0.4.40", default-features = false }
tempfile = "3.8.0" tempfile = "3.8.0"
termcolor = "1.2.0"
thiserror = "1.0.47" thiserror = "1.0.47"
time = { version = "0.3", features = ["parsing", "formatting", "serde"] } time = { version = "0.3", features = ["parsing", "formatting", "serde"] }
toml = "0.7.6" toml = "0.7.6"
@ -124,7 +121,6 @@ path = "src/cargo/lib.rs"
[dependencies] [dependencies]
anstream.workspace = true anstream.workspace = true
anstyle-termcolor.workspace = true
anstyle.workspace = true anstyle.workspace = true
anyhow.workspace = true anyhow.workspace = true
base64.workspace = true base64.workspace = true
@ -179,7 +175,6 @@ shell-escape.workspace = true
syn.workspace = true syn.workspace = true
tar.workspace = true tar.workspace = true
tempfile.workspace = true tempfile.workspace = true
termcolor.workspace = true
time.workspace = true time.workspace = true
toml.workspace = true toml.workspace = true
toml_edit.workspace = true toml_edit.workspace = true
@ -194,9 +189,6 @@ walkdir.workspace = true
[target.'cfg(not(windows))'.dependencies] [target.'cfg(not(windows))'.dependencies]
openssl = { workspace = true, optional = true } openssl = { workspace = true, optional = true }
[target.'cfg(windows)'.dependencies]
fwdansi.workspace = true
[target.'cfg(windows)'.dependencies.windows-sys] [target.'cfg(windows)'.dependencies.windows-sys]
workspace = true workspace = true
features = [ features = [

View file

@ -2,9 +2,8 @@ use std::fmt;
use std::io::prelude::*; use std::io::prelude::*;
use std::io::IsTerminal; use std::io::IsTerminal;
use anstream::AutoStream;
use anstyle::Style; use anstyle::Style;
use anstyle_termcolor::to_termcolor_spec;
use termcolor::{self, BufferWriter, StandardStream, WriteColor};
use crate::util::errors::CargoResult; use crate::util::errors::CargoResult;
use crate::util::style::*; use crate::util::style::*;
@ -81,15 +80,9 @@ enum ShellOut {
/// A plain write object without color support /// A plain write object without color support
Write(Box<dyn Write>), Write(Box<dyn Write>),
/// Color-enabled stdio, with information on whether color should be used /// Color-enabled stdio, with information on whether color should be used
///
/// The separate buffered fields are used for buffered writing to the
/// corresponding stream. The non-buffered fields should be used when you
/// do not want content to be buffered.
Stream { Stream {
stdout: StandardStream, stdout: AutoStream<std::io::Stdout>,
buffered_stdout: BufferWriter, stderr: AutoStream<std::io::Stderr>,
stderr: StandardStream,
buffered_stderr: BufferWriter,
stderr_tty: bool, stderr_tty: bool,
color_choice: ColorChoice, color_choice: ColorChoice,
}, },
@ -111,15 +104,13 @@ impl Shell {
/// output. /// output.
pub fn new() -> Shell { pub fn new() -> Shell {
let auto_clr = ColorChoice::CargoAuto; let auto_clr = ColorChoice::CargoAuto;
let stdout_choice = auto_clr.to_termcolor_color_choice(Stream::Stdout); let stdout_choice = auto_clr.to_anstream_color_choice();
let stderr_choice = auto_clr.to_termcolor_color_choice(Stream::Stderr); let stderr_choice = auto_clr.to_anstream_color_choice();
Shell { Shell {
output: ShellOut::Stream { output: ShellOut::Stream {
stdout: StandardStream::stdout(stdout_choice), stdout: AutoStream::new(std::io::stdout(), stdout_choice),
buffered_stdout: BufferWriter::stdout(stdout_choice), stderr: AutoStream::new(std::io::stderr(), stderr_choice),
stderr: StandardStream::stderr(stderr_choice), color_choice: auto_clr,
buffered_stderr: BufferWriter::stderr(stderr_choice),
color_choice: ColorChoice::CargoAuto,
stderr_tty: std::io::stderr().is_terminal(), stderr_tty: std::io::stderr().is_terminal(),
}, },
verbosity: Verbosity::Verbose, verbosity: Verbosity::Verbose,
@ -297,9 +288,7 @@ impl Shell {
pub fn set_color_choice(&mut self, color: Option<&str>) -> CargoResult<()> { pub fn set_color_choice(&mut self, color: Option<&str>) -> CargoResult<()> {
if let ShellOut::Stream { if let ShellOut::Stream {
ref mut stdout, ref mut stdout,
ref mut buffered_stdout,
ref mut stderr, ref mut stderr,
ref mut buffered_stderr,
ref mut color_choice, ref mut color_choice,
.. ..
} = self.output } = self.output
@ -317,12 +306,10 @@ impl Shell {
), ),
}; };
*color_choice = cfg; *color_choice = cfg;
let stdout_choice = cfg.to_termcolor_color_choice(Stream::Stdout); let stdout_choice = cfg.to_anstream_color_choice();
let stderr_choice = cfg.to_termcolor_color_choice(Stream::Stderr); let stderr_choice = cfg.to_anstream_color_choice();
*stdout = StandardStream::stdout(stdout_choice); *stdout = AutoStream::new(std::io::stdout(), stdout_choice);
*buffered_stdout = BufferWriter::stdout(stdout_choice); *stderr = AutoStream::new(std::io::stderr(), stderr_choice);
*stderr = StandardStream::stderr(stderr_choice);
*buffered_stderr = BufferWriter::stderr(stderr_choice);
} }
Ok(()) Ok(())
} }
@ -342,14 +329,14 @@ impl Shell {
pub fn err_supports_color(&self) -> bool { pub fn err_supports_color(&self) -> bool {
match &self.output { match &self.output {
ShellOut::Write(_) => false, ShellOut::Write(_) => false,
ShellOut::Stream { stderr, .. } => stderr.supports_color(), ShellOut::Stream { stderr, .. } => supports_color(stderr.current_choice()),
} }
} }
pub fn out_supports_color(&self) -> bool { pub fn out_supports_color(&self) -> bool {
match &self.output { match &self.output {
ShellOut::Write(_) => false, ShellOut::Write(_) => false,
ShellOut::Stream { stdout, .. } => stdout.supports_color(), ShellOut::Stream { stdout, .. } => supports_color(stdout.current_choice()),
} }
} }
@ -372,13 +359,6 @@ impl Shell {
if self.needs_clear { if self.needs_clear {
self.err_erase_line(); self.err_erase_line();
} }
#[cfg(windows)]
{
if let ShellOut::Stream { stderr, .. } = &mut self.output {
::fwdansi::write_ansi(stderr, message)?;
return Ok(());
}
}
self.err().write_all(message)?; self.err().write_all(message)?;
Ok(()) Ok(())
} }
@ -388,13 +368,6 @@ impl Shell {
if self.needs_clear { if self.needs_clear {
self.err_erase_line(); self.err_erase_line();
} }
#[cfg(windows)]
{
if let ShellOut::Stream { stdout, .. } = &mut self.output {
::fwdansi::write_ansi(stdout, message)?;
return Ok(());
}
}
self.out().write_all(message)?; self.out().write_all(message)?;
Ok(()) Ok(())
} }
@ -426,26 +399,22 @@ impl ShellOut {
justified: bool, justified: bool,
) -> CargoResult<()> { ) -> CargoResult<()> {
match *self { match *self {
ShellOut::Stream { ShellOut::Stream { ref mut stderr, .. } => {
ref mut buffered_stderr, let style = style.render();
.. let bold = (anstyle::Style::new() | anstyle::Effects::BOLD).render();
} => { let reset = anstyle::Reset.render();
let mut buffer = buffered_stderr.buffer();
buffer.reset()?; let mut buffer = Vec::new();
buffer.set_color(&to_termcolor_spec(*style))?;
if justified { if justified {
write!(buffer, "{:>12}", status)?; write!(&mut buffer, "{style}{status:>12}{reset}")?;
} else { } else {
write!(buffer, "{}", status)?; write!(&mut buffer, "{style}{status}{reset}{bold}:{reset}")?;
buffer.set_color(termcolor::ColorSpec::new().set_bold(true))?;
write!(buffer, ":")?;
} }
buffer.reset()?;
match message { match message {
Some(message) => writeln!(buffer, " {}", message)?, Some(message) => writeln!(buffer, " {message}")?,
None => write!(buffer, " ")?, None => write!(buffer, " ")?,
} }
buffered_stderr.print(&buffer)?; stderr.write_all(&buffer)?;
} }
ShellOut::Write(ref mut w) => { ShellOut::Write(ref mut w) => {
if justified { if justified {
@ -463,18 +432,15 @@ impl ShellOut {
} }
/// Write a styled fragment /// Write a styled fragment
fn write_stdout(&mut self, fragment: impl fmt::Display, color: &Style) -> CargoResult<()> { fn write_stdout(&mut self, fragment: impl fmt::Display, style: &Style) -> CargoResult<()> {
match *self { match *self {
ShellOut::Stream { ShellOut::Stream { ref mut stdout, .. } => {
ref mut buffered_stdout, let style = style.render();
.. let reset = anstyle::Reset.render();
} => {
let mut buffer = buffered_stdout.buffer(); let mut buffer = Vec::new();
buffer.reset()?; write!(buffer, "{style}{}{reset}", fragment)?;
buffer.set_color(&to_termcolor_spec(*color))?; stdout.write_all(&buffer)?;
write!(buffer, "{}", fragment)?;
buffer.reset()?;
buffered_stdout.print(&buffer)?;
} }
ShellOut::Write(ref mut w) => { ShellOut::Write(ref mut w) => {
write!(w, "{}", fragment)?; write!(w, "{}", fragment)?;
@ -484,18 +450,15 @@ impl ShellOut {
} }
/// Write a styled fragment /// Write a styled fragment
fn write_stderr(&mut self, fragment: impl fmt::Display, color: &Style) -> CargoResult<()> { fn write_stderr(&mut self, fragment: impl fmt::Display, style: &Style) -> CargoResult<()> {
match *self { match *self {
ShellOut::Stream { ShellOut::Stream { ref mut stderr, .. } => {
ref mut buffered_stderr, let style = style.render();
.. let reset = anstyle::Reset.render();
} => {
let mut buffer = buffered_stderr.buffer(); let mut buffer = Vec::new();
buffer.reset()?; write!(buffer, "{style}{}{reset}", fragment)?;
buffer.set_color(&to_termcolor_spec(*color))?; stderr.write_all(&buffer)?;
write!(buffer, "{}", fragment)?;
buffer.reset()?;
buffered_stderr.print(&buffer)?;
} }
ShellOut::Write(ref mut w) => { ShellOut::Write(ref mut w) => {
write!(w, "{}", fragment)?; write!(w, "{}", fragment)?;
@ -522,33 +485,22 @@ impl ShellOut {
} }
impl ColorChoice { impl ColorChoice {
/// Converts our color choice to termcolor's version. /// Converts our color choice to anstream's version.
fn to_termcolor_color_choice(self, stream: Stream) -> termcolor::ColorChoice { fn to_anstream_color_choice(self) -> anstream::ColorChoice {
match self { match self {
ColorChoice::Always => termcolor::ColorChoice::Always, ColorChoice::Always => anstream::ColorChoice::Always,
ColorChoice::Never => termcolor::ColorChoice::Never, ColorChoice::Never => anstream::ColorChoice::Never,
ColorChoice::CargoAuto => { ColorChoice::CargoAuto => anstream::ColorChoice::Auto,
if stream.is_terminal() {
termcolor::ColorChoice::Auto
} else {
termcolor::ColorChoice::Never
}
}
} }
} }
} }
enum Stream { fn supports_color(choice: anstream::ColorChoice) -> bool {
Stdout, match choice {
Stderr, anstream::ColorChoice::Always
} | anstream::ColorChoice::AlwaysAnsi
| anstream::ColorChoice::Auto => true,
impl Stream { anstream::ColorChoice::Never => false,
fn is_terminal(self) -> bool {
match self {
Self::Stdout => std::io::stdout().is_terminal(),
Self::Stderr => std::io::stderr().is_terminal(),
}
} }
} }