ANSI color is not retained across multiple `print(ln)!`'s in Windows legacy console
Cargo.toml
[package]
name = "anstream-test"
version = "0.1.0"
edition = "2021"
[dependencies]
anstream = "0.6.18"
src/main.rs
use anstream::{print, println};
fn main() {
print!("\x1b[90m(print!) This text is displayed in gray.\n");
print!("(print!) This text should also be displayed in gray.\n");
println!("\x1b[90m(println!) This text is displayed in gray.");
println!("(println!) This text should also be displayed in gray.\x1b[0m");
}
Steps to reproduce
Run cargo run in CMD/PowerShell with 'Legacy Console mode' enabled.
Expected result
All the lines should be displayed in gray, just like in the non-legacy Windows Console.
Actual result
Only the lines that output \x1b[90m are displayed in gray (1st and 3rd lines).
Environment
- Windows 10 22H2 Home x64
10.0.19045.5011 - Visual Studio Community 2022
17.11.5/ Windows 11 SDK10.0.26100.0 - Default host:
x86_64-pc-windows-msvc - Active toolchain:
stable-x86_64-pc-windows-msvc(default) / rustc1.82.0(f6e511eec 2024-10-15)
Each println! call will call stdout
https://github.com/rust-cli/anstyle/blob/fabe0c31e56a8f4cec5bda325dfafbe773ef6621/crates/anstream/src/_macros.rs#L130-L151
Each stdout call creates a new AutoStream
https://github.com/rust-cli/anstyle/blob/fabe0c31e56a8f4cec5bda325dfafbe773ef6621/crates/anstream/src/lib.rs#L70-L73
AutoStream is stateless, forwarding on calls
https://github.com/rust-cli/anstyle/blob/fabe0c31e56a8f4cec5bda325dfafbe773ef6621/crates/anstream/src/auto.rs#L256-L262
WinconStream is stateful but only within an instance and not across instances
https://github.com/rust-cli/anstyle/blob/fabe0c31e56a8f4cec5bda325dfafbe773ef6621/crates/anstream/src/wincon.rs#L115-L131
The next layer down of WinconStream only deals with global for tracking the original colors of the terminal
https://github.com/rust-cli/anstyle/blob/fabe0c31e56a8f4cec5bda325dfafbe773ef6621/crates/anstyle-wincon/src/stream.rs#L140-L150
During one of the redesigns, I had explored keeping global state to "remember" where we left off between instances of WinconStream I think the big problem I ran into was that the stream would be unlocked and I couldn't guarantee what happened to the output between instances. This was assuming someone was explicitly acquiring and releasing the AutoStream for complete messages. The interaction of this with println, especially with a user intentionally bleeding output across calls, was overlooked in this case.
The easy workaround is to call stdout() and write to it, especially locking it. Writing to locked output is already a best practice because of how slow individual print calls can be from acquiring and releasing the lock (Rust-wide and not just our wrappers).
As for fixing this, we'll need to think on this more of what we want to optimize for and what is the right answer.