Skip to content

Commit 59596f0

Browse files
committed
Auto merge of #12751 - epage:color, r=arlosi
refactor: Switch from termcolor to anstream ### What does this PR try to resolve? `anstream` asks the question "what if you took `fwdansi` and removed `termcolor` underneath it. It wraps output streams, adapting ANSI escape codes to what is needed - Pass through if its supported - Strip if its not - Adapt to wincon API if needed Benefits - Lower boilerplate: we can use `write!` with styled text rather than the back-and-forth between colors and writing that termcolor needs - Allows richer styling as `Shell` can accept styled messages and adapt them as needed Side effects - We'll now respect [NO_COLOR](https://no-color.org/), [CLICOLOR_FORCE](https://bixense.com/clicolors/), and [CLICOLOR](jhasse/clicolors@3a22aaa) Fixes #12627 ### How should we test and review this PR? This is broken up by commits for easier browsing. However, as there aren't really tests for colored output, this needs hand inspection to verify ### Additional information This allowed us to remove the need for stripping ansi escape codes completely. Even if it didn't, it exposes its internal stripping API for reuse, saving on a dependency and being significantly faster.
2 parents 84445c6 + a770d36 commit 59596f0

File tree

8 files changed

+105
-294
lines changed

8 files changed

+105
-294
lines changed

Cargo.lock

Lines changed: 17 additions & 84 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ edition = "2021"
1616
license = "MIT OR Apache-2.0"
1717

1818
[workspace.dependencies]
19-
anstyle = "1.0.3"
20-
anstyle-termcolor = "1.1.0"
19+
anstream = "0.6.3"
20+
anstyle = "1.0.4"
2121
anyhow = "1.0.75"
2222
base64 = "0.21.3"
2323
bytesize = "1.3"
@@ -31,7 +31,7 @@ cargo-test-macro = { path = "crates/cargo-test-macro" }
3131
cargo-test-support = { path = "crates/cargo-test-support" }
3232
cargo-util = { version = "0.2.6", path = "crates/cargo-util" }
3333
cargo_metadata = "0.17.0"
34-
clap = "4.4.4"
34+
clap = "4.4.6"
3535
color-print = "0.3.4"
3636
core-foundation = { version = "0.9.3", features = ["mac_os_10_7_support"] }
3737
crates-io = { version = "0.39.0", path = "crates/crates-io" }
@@ -40,7 +40,6 @@ curl = "0.4.44"
4040
curl-sys = "0.4.66"
4141
filetime = "0.2.22"
4242
flate2 = { version = "1.0.27", default-features = false, features = ["zlib"] }
43-
fwdansi = "1.1.0"
4443
git2 = "0.18.0"
4544
git2-curl = "0.19.0"
4645
gix = { version = "0.54.1", default-features = false, features = ["blocking-http-transport-curl", "progress-tree", "revision"] }
@@ -86,12 +85,10 @@ serde_json = "1.0.105"
8685
sha1 = "0.10.5"
8786
sha2 = "0.10.7"
8887
shell-escape = "0.1.5"
89-
snapbox = { version = "0.4.12", features = ["diff", "path"] }
90-
strip-ansi-escapes = "0.1.1"
88+
snapbox = { version = "0.4.13", features = ["diff", "path"] }
9189
syn = { version = "2.0.29", features = ["extra-traits", "full"] }
9290
tar = { version = "0.4.40", default-features = false }
9391
tempfile = "3.8.0"
94-
termcolor = "1.2.0"
9592
thiserror = "1.0.47"
9693
time = { version = "0.3", features = ["parsing", "formatting", "serde"] }
9794
toml = "0.7.6"
@@ -123,8 +120,8 @@ name = "cargo"
123120
path = "src/cargo/lib.rs"
124121

125122
[dependencies]
123+
anstream.workspace = true
126124
anstyle.workspace = true
127-
anstyle-termcolor.workspace = true
128125
anyhow.workspace = true
129126
base64.workspace = true
130127
bytesize.workspace = true
@@ -175,11 +172,9 @@ serde_ignored.workspace = true
175172
serde_json = { workspace = true, features = ["raw_value"] }
176173
sha1.workspace = true
177174
shell-escape.workspace = true
178-
strip-ansi-escapes.workspace = true
179175
syn.workspace = true
180176
tar.workspace = true
181177
tempfile.workspace = true
182-
termcolor.workspace = true
183178
time.workspace = true
184179
toml.workspace = true
185180
toml_edit.workspace = true
@@ -194,9 +189,6 @@ walkdir.workspace = true
194189
[target.'cfg(not(windows))'.dependencies]
195190
openssl = { workspace = true, optional = true }
196191

197-
[target.'cfg(windows)'.dependencies]
198-
fwdansi.workspace = true
199-
200192
[target.'cfg(windows)'.dependencies.windows-sys]
201193
workspace = true
202194
features = [

crates/cargo-test-support/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ publish = false
1010
doctest = false
1111

1212
[dependencies]
13+
anstream.workspace = true
14+
anstyle.workspace = true
1315
anyhow.workspace = true
1416
cargo-test-macro.workspace = true
1517
cargo-util.workspace = true
@@ -24,7 +26,6 @@ serde = { workspace = true, features = ["derive"] }
2426
serde_json.workspace = true
2527
snapbox.workspace = true
2628
tar.workspace = true
27-
termcolor.workspace = true
2829
time.workspace = true
2930
toml.workspace = true
3031
url.workspace = true

crates/cargo-test-support/src/diff.rs

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
88
use std::fmt;
99
use std::io::Write;
10-
use termcolor::{Ansi, Color, ColorSpec, NoColor, WriteColor};
1110

1211
/// A single line change to be applied to the original.
1312
#[derive(Debug, Eq, PartialEq)]
@@ -111,42 +110,35 @@ where
111110
}
112111

113112
pub fn render_colored_changes<T: fmt::Display>(changes: &[Change<T>]) -> String {
114-
// termcolor is not very ergonomic, but I don't want to bring in another dependency.
115-
let mut red = ColorSpec::new();
116-
red.set_fg(Some(Color::Red));
117-
let mut green = ColorSpec::new();
118-
green.set_fg(Some(Color::Green));
119-
let mut dim = ColorSpec::new();
120-
dim.set_dimmed(true);
121-
let mut v = Vec::new();
122-
let mut result: Box<dyn WriteColor> = if crate::is_ci() {
113+
// anstyle is not very ergonomic, but I don't want to bring in another dependency.
114+
let red = anstyle::AnsiColor::Red.on_default().render();
115+
let green = anstyle::AnsiColor::Green.on_default().render();
116+
let dim = (anstyle::Style::new() | anstyle::Effects::DIMMED).render();
117+
let bold = (anstyle::Style::new() | anstyle::Effects::BOLD).render();
118+
let reset = anstyle::Reset.render();
119+
120+
let choice = if crate::is_ci() {
123121
// Don't use color on CI. Even though GitHub can display colors, it
124122
// makes reading the raw logs more difficult.
125-
Box::new(NoColor::new(&mut v))
123+
anstream::ColorChoice::Never
126124
} else {
127-
Box::new(Ansi::new(&mut v))
125+
anstream::AutoStream::choice(&std::io::stdout())
128126
};
127+
let mut buffer = anstream::AutoStream::new(Vec::new(), choice);
129128

130129
for change in changes {
131130
let (nums, sign, color, text) = match change {
132-
Change::Add(i, s) => (format!(" {:<4} ", i), '+', &green, s),
133-
Change::Remove(i, s) => (format!("{:<4} ", i), '-', &red, s),
134-
Change::Keep(x, y, s) => (format!("{:<4}{:<4} ", x, y), ' ', &dim, s),
131+
Change::Add(i, s) => (format!(" {:<4} ", i), '+', green, s),
132+
Change::Remove(i, s) => (format!("{:<4} ", i), '-', red, s),
133+
Change::Keep(x, y, s) => (format!("{:<4}{:<4} ", x, y), ' ', dim, s),
135134
};
136-
result.set_color(&dim).unwrap();
137-
write!(result, "{}", nums).unwrap();
138-
let mut bold = color.clone();
139-
bold.set_bold(true);
140-
result.set_color(&bold).unwrap();
141-
write!(result, "{}", sign).unwrap();
142-
result.reset().unwrap();
143-
result.set_color(&color).unwrap();
144-
write!(result, "{}", text).unwrap();
145-
result.reset().unwrap();
146-
writeln!(result).unwrap();
135+
write!(
136+
buffer,
137+
"{dim}{nums}{reset}{bold}{sign}{reset}{color}{text}{reset}"
138+
)
139+
.unwrap();
147140
}
148-
drop(result);
149-
String::from_utf8(v).unwrap()
141+
String::from_utf8(buffer.into_inner()).unwrap()
150142
}
151143

152144
#[cfg(test)]

0 commit comments

Comments
 (0)