Skip to content

Commit 0994b8a

Browse files
de-vri-esjakoschiko
authored andcommitted
Add function to test if terminal supports ANSI color codes.
1 parent 0df6e33 commit 0994b8a

File tree

3 files changed

+42
-10
lines changed

3 files changed

+42
-10
lines changed

library/test/src/term.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ pub trait Terminal: Write {
7171
/// if there was an I/O error.
7272
fn fg(&mut self, color: color::Color) -> io::Result<bool>;
7373

74+
/// Returns `true` if the terminal supports ANSI color codes.
75+
///
76+
/// ANSI color codes can be buffered along with the output,
77+
/// but not all Windows terminals support them.
78+
fn supports_ansi_colors(&self) -> bool;
79+
7480
/// Resets all terminal attributes and colors to their defaults.
7581
///
7682
/// Returns `Ok(true)` if the terminal was reset, `Ok(false)` otherwise, and `Err(e)` if there

library/test/src/term/terminfo/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ impl<T: Write + Send> Terminal for TerminfoTerminal<T> {
125125
Ok(false)
126126
}
127127

128+
fn supports_ansi_colors(&self) -> bool {
129+
self.num_colors > 0
130+
}
131+
128132
fn reset(&mut self) -> io::Result<bool> {
129133
// are there any terminals that have color/attrs and not sgr0?
130134
// Try falling back to sgr, then op

library/test/src/term/win.rs

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ struct CONSOLE_SCREEN_BUFFER_INFO {
5353
#[link(name = "kernel32")]
5454
extern "system" {
5555
fn SetConsoleTextAttribute(handle: HANDLE, attr: WORD) -> BOOL;
56+
fn GetConsoleMode(handle: HANDLE, mode: *mut DWORD) -> BOOL;
5657
fn GetStdHandle(which: DWORD) -> HANDLE;
5758
fn GetConsoleScreenBufferInfo(handle: HANDLE, info: *mut CONSOLE_SCREEN_BUFFER_INFO) -> BOOL;
5859
}
@@ -91,24 +92,30 @@ fn bits_to_color(bits: u16) -> color::Color {
9192
color | (u32::from(bits) & 0x8) // copy the hi-intensity bit
9293
}
9394

95+
fn get_stdout_handle() -> HANDLE {
96+
unsafe {
97+
// Magic -11 means stdout, from
98+
// https://docs.microsoft.com/en-us/windows/console/getstdhandle
99+
//
100+
// You may be wondering, "but what about stderr?", and the answer
101+
// to that is that setting terminal attributes on the stdout
102+
// handle also sets them for stderr, since they go to the same
103+
// terminal! Admittedly, this is fragile, since stderr could be
104+
// redirected to a different console. This is good enough for
105+
// rustc though. See #13400.
106+
GetStdHandle(-11i32 as DWORD)
107+
}
108+
}
109+
94110
impl<T: Write + Send + 'static> WinConsole<T> {
95111
fn apply(&mut self) {
96112
let _unused = self.buf.flush();
97113
let mut accum: WORD = 0;
98114
accum |= color_to_bits(self.foreground);
99115
accum |= color_to_bits(self.background) << 4;
100116

117+
let out = get_stdout_handle();
101118
unsafe {
102-
// Magic -11 means stdout, from
103-
// https://docs.microsoft.com/en-us/windows/console/getstdhandle
104-
//
105-
// You may be wondering, "but what about stderr?", and the answer
106-
// to that is that setting terminal attributes on the stdout
107-
// handle also sets them for stderr, since they go to the same
108-
// terminal! Admittedly, this is fragile, since stderr could be
109-
// redirected to a different console. This is good enough for
110-
// rustc though. See #13400.
111-
let out = GetStdHandle(-11i32 as DWORD);
112119
SetConsoleTextAttribute(out, accum);
113120
}
114121
}
@@ -160,6 +167,21 @@ impl<T: Write + Send + 'static> Terminal for WinConsole<T> {
160167
Ok(true)
161168
}
162169

170+
fn supports_ansi_colors(&self) -> bool {
171+
// From https://docs.microsoft.com/en-us/windows/console/getconsolemode
172+
const ENABLE_VIRTUAL_TERMINAL_PROCESSING: DWORD = 0x0004;
173+
174+
let stdout = get_stdout_handle();
175+
let mut mode: DWORD = 0;
176+
unsafe {
177+
if GetConsoleMode(stdout, &mut mode) != 0 {
178+
mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0
179+
} else {
180+
false
181+
}
182+
}
183+
}
184+
163185
fn reset(&mut self) -> io::Result<bool> {
164186
self.foreground = self.def_foreground;
165187
self.background = self.def_background;

0 commit comments

Comments
 (0)