Skip to content

Commit 46413dd

Browse files
committed
WIP: Adopt concolor-control for auto-detection
This is a PoC to collect feedback on a crate meant improve interoperability across various colored output crates. I'm a little uncertain on the `Buffer` - It handles `console` differently than `WriterInner` - I used the lowest common denominator of the streams but I wonder if we should add support for completely skipping stream detection For more on the motivation, see rust-cli/team#15 (comment)
1 parent dc7e7b9 commit 46413dd

File tree

2 files changed

+34
-61
lines changed

2 files changed

+34
-61
lines changed

Cargo.toml

+7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ edition = "2018"
1818
name = "termcolor"
1919
bench = false
2020

21+
[features]
22+
default = ["auto"]
23+
auto = ["concolor-control/auto"]
24+
25+
[dependencies]
26+
concolor-control = { version = "0.0.6", default-features = false }
27+
2128
[target.'cfg(windows)'.dependencies]
2229
winapi-util = "0.1.3"
2330

src/lib.rs

+27-61
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ Currently, `termcolor` does not provide anything to do this for you.
124124
// #[cfg(doctest)]
125125
// doctest!("../README.md");
126126

127-
use std::env;
128127
use std::error;
129128
use std::fmt;
130129
use std::io::{self, Write};
@@ -221,72 +220,26 @@ pub enum ColorChoice {
221220

222221
impl ColorChoice {
223222
/// Returns true if we should attempt to write colored output.
224-
fn should_attempt_color(&self) -> bool {
223+
fn should_attempt_color(&self, stream: concolor_control::Stream) -> bool {
225224
match *self {
226225
ColorChoice::Always => true,
227226
ColorChoice::AlwaysAnsi => true,
228227
ColorChoice::Never => false,
229-
ColorChoice::Auto => self.env_allows_color(),
228+
ColorChoice::Auto => concolor_control::get(stream).color(),
230229
}
231230
}
232231

233-
#[cfg(not(windows))]
234-
fn env_allows_color(&self) -> bool {
235-
match env::var_os("TERM") {
236-
// If TERM isn't set, then we are in a weird environment that
237-
// probably doesn't support colors.
238-
None => return false,
239-
Some(k) => {
240-
if k == "dumb" {
241-
return false;
242-
}
243-
}
244-
}
245-
// If TERM != dumb, then the only way we don't allow colors at this
246-
// point is if NO_COLOR is set.
247-
if env::var_os("NO_COLOR").is_some() {
248-
return false;
249-
}
250-
true
251-
}
252-
253-
#[cfg(windows)]
254-
fn env_allows_color(&self) -> bool {
255-
// On Windows, if TERM isn't set, then we shouldn't automatically
256-
// assume that colors aren't allowed. This is unlike Unix environments
257-
// where TERM is more rigorously set.
258-
if let Some(k) = env::var_os("TERM") {
259-
if k == "dumb" {
260-
return false;
261-
}
262-
}
263-
// If TERM != dumb, then the only way we don't allow colors at this
264-
// point is if NO_COLOR is set.
265-
if env::var_os("NO_COLOR").is_some() {
266-
return false;
267-
}
268-
true
269-
}
270-
271232
/// Returns true if this choice should forcefully use ANSI color codes.
272233
///
273234
/// It's possible that ANSI is still the correct choice even if this
274235
/// returns false.
275236
#[cfg(windows)]
276-
fn should_ansi(&self) -> bool {
237+
fn should_ansi(&self, stream: concolor_control::Stream) -> bool {
277238
match *self {
278239
ColorChoice::Always => false,
279240
ColorChoice::AlwaysAnsi => true,
280241
ColorChoice::Never => false,
281-
ColorChoice::Auto => {
282-
match env::var("TERM") {
283-
Err(_) => false,
284-
// cygwin doesn't seem to support ANSI escape sequences
285-
// and instead has its own variety. However, the Windows
286-
// console API may be available.
287-
Ok(k) => k != "dumb" && k != "cygwin",
288-
}
289-
}
242+
ColorChoice::Auto => concolor_control::get(stream).ansi_color(),
290243
}
291244
}
292245
}
@@ -295,13 +248,29 @@ impl ColorChoice {
295248
/// separate types, which makes it difficult to abstract over them. We use
296249
/// some simple internal enum types to work around this.
297250
251+
#[derive(Copy, Clone)]
298252
enum StandardStreamType {
299253
Stdout,
300254
Stderr,
301255
StdoutBuffered,
302256
StderrBuffered,
303257
}
304258

259+
impl StandardStreamType {
260+
fn to_concolor(self) -> concolor_control::Stream {
261+
match self {
262+
StandardStreamType::Stdout => concolor_control::Stream::Stdout,
263+
StandardStreamType::Stderr => concolor_control::Stream::Stderr,
264+
StandardStreamType::StdoutBuffered => {
265+
concolor_control::Stream::Stdout
266+
}
267+
StandardStreamType::StderrBuffered => {
268+
concolor_control::Stream::Stderr
269+
}
270+
}
271+
}
272+
}
273+
305274
enum IoStandardStream {
306275
Stdout(io::Stdout),
307276
Stderr(io::Stderr),
@@ -558,7 +527,7 @@ impl WriterInner<IoStandardStream> {
558527
sty: StandardStreamType,
559528
choice: ColorChoice,
560529
) -> WriterInner<IoStandardStream> {
561-
if choice.should_attempt_color() {
530+
if choice.should_attempt_color(sty.to_concolor()) {
562531
WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
563532
} else {
564533
WriterInner::NoColor(NoColor(IoStandardStream::new(sty)))
@@ -581,12 +550,8 @@ impl WriterInner<IoStandardStream> {
581550
StandardStreamType::StdoutBuffered => wincon::Console::stdout(),
582551
StandardStreamType::StderrBuffered => wincon::Console::stderr(),
583552
};
584-
let is_console_virtual = con
585-
.as_mut()
586-
.map(|con| con.set_virtual_terminal_processing(true).is_ok())
587-
.unwrap_or(false);
588-
if choice.should_attempt_color() {
589-
if choice.should_ansi() || is_console_virtual {
553+
if choice.should_attempt_color(sty.to_concolor()) {
554+
if choice.should_ansi(sty.to_concolor()) {
590555
WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
591556
} else if let Ok(console) = con {
592557
WriterInner::Windows {
@@ -1033,7 +998,7 @@ impl Buffer {
1033998
/// Create a new buffer with the given color settings.
1034999
#[cfg(not(windows))]
10351000
fn new(choice: ColorChoice) -> Buffer {
1036-
if choice.should_attempt_color() {
1001+
if choice.should_attempt_color(concolor_control::Stream::Either) {
10371002
Buffer::ansi()
10381003
} else {
10391004
Buffer::no_color()
@@ -1049,8 +1014,9 @@ impl Buffer {
10491014
/// sequences are used instead.
10501015
#[cfg(windows)]
10511016
fn new(choice: ColorChoice, console: bool) -> Buffer {
1052-
if choice.should_attempt_color() {
1053-
if !console || choice.should_ansi() {
1017+
if choice.should_attempt_color(concolor_control::Stream::Either) {
1018+
if !console || choice.should_ansi(concolor_control::Stream::Either)
1019+
{
10541020
Buffer::ansi()
10551021
} else {
10561022
Buffer::console()

0 commit comments

Comments
 (0)