crossterm-rs / crossterm

Cross platform terminal library rust
MIT License
3.3k stars 280 forks source link

`Display` on `StyledObject` is not working well with WinApi #262

Open MaulingMonkey opened 5 years ago

MaulingMonkey commented 5 years ago

This works fine on windows 10, but appears completely unstyled on windows 7:

use crossterm::*;

fn main() {
    println!("{} {} {}", "fore".black(),        "back".on_black(),      "Black");
    println!("{} {} {}", "fore".dark_grey(),    "back".on_dark_grey(),  "Dark Grey");
    println!("{} {} {}", "fore".grey(),         "back".on_grey(),       "Grey");
    println!("{} {} {}", "fore".white(),        "back".on_white(),      "White");
}

With enough flushing, you can kinda get it to work:

use crossterm_style::*;
use std::io::{stdout, Write};

fn main() {
    for color in &[Color::Black, Color::DarkGrey, Color::Grey, Color::White] {
        let color = *color;
        print!("{}", Colored::Fg(color));
        stdout().flush().unwrap();
        print!("fore");
        stdout().flush().unwrap();
        print!("{}", Colored::Fg(Color::Reset));
        stdout().flush().unwrap();
        print!(" ");
        stdout().flush().unwrap();
        print!("{}", Colored::Bg(color));
        stdout().flush().unwrap();
        print!("back");
        stdout().flush().unwrap();
        print!("{}", Colored::Bg(Color::Reset));
        stdout().flush().unwrap();
        print!(" {:?}", color);
        stdout().flush().unwrap();
        println!();
    }
}
MaulingMonkey commented 5 years ago

Might be worth introducing an env var or feature or something to force legacy winapi mode for testing purpouses on win10 systems.

TimonPost commented 5 years ago

Related to old issue: https://github.com/crossterm-rs/crossterm/issues/38 it is very strange behavior and probably has to with the order in which rust invokes the Display implemented for tose types and then how WinApi set's those collars. It is unclear to me why this happens. It was partaly solved in earlier releases. But there are still some problems with it. I will not this issue as a bug

andrewhickman commented 4 years ago

It seems like this could be fixed by flushing before (or after) every winapi call?

TimonPost commented 4 years ago

The problem arises when you print at the same line. If you set style, print a string without line break and then set the style back, and then flush you won't have styled text.

Maybe this can be solved by using winapi for writing as well.

sigmaSd commented 4 years ago

To summarize the issue:

let x = format!("{}", hello".red());

This can easily work with ansi since the ansi sequence is written to x with the original str. In winapi case, the corresponding api is called and we never modify the original str, so the color information is lost (which is the expected behavior) so when we print later it will only color in ansi's case. I think formatting and winapi simply can't coexist together, we should just mention it in the docs and that should be enough.