console-rs / indicatif

A command line progress reporting library for Rust
MIT License
4.43k stars 243 forks source link

`MultiProgress:println` doesn't behave correctly when no progress bars have been added yet #447

Open chris-laplante opened 2 years ago

chris-laplante commented 2 years ago

Try this render test:

#[test]
fn multi_progress_println_newline() {
    let in_mem = InMemoryTerm::new(10, 10);
    let mp =
        MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone())));

    mp.println("This line is tooooooo long for the terminal\r\n").unwrap();
    mp.println("but it should wrap correctly\r\n").unwrap();

    assert_eq!(in_mem.contents(), "This line\nis toooooo\no long for\n the termi\nnal\nbut it sho\nuld wrap c\norrectly");
}

It fails like this:

---- multi_progress_println_newline stdout ----
thread 'multi_progress_println_newline' panicked at 'assertion failed: `(left == right)`
  left: `"This line\nis toooooo\no long for\n the termi\nnalbut it\nshould wra\np correctl\ny"`,
 right: `"This line\nis toooooo\no long for\n the termi\nnal\nbut it sho\nuld wrap c\norrectly"`', tests/render.rs:607:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

The issue is that the underlying DrawState::draw_to_term method assumes that the last line to be drawn doesn't contain a newline. This is true when progress bars are involved, but not true when just calling MultiProgress:println with no progress bars.

I think we need to add some extra logic to draw_to_term so that it behaves differently when no progress bars are present.

The workaround I am using right now is to just use MultiProgress::suspend and then use eprintln! inside that.

chris-laplante commented 2 years ago

FYI this is related to #442 I think

djc commented 2 years ago

I think we need to add some extra logic to draw_to_term so that it behaves differently when no progress bars are present.

Seems reasonable.

Ekleog commented 1 year ago

FWIW, this is what it manifests as:

Screenshot from 2023-02-07 00-18-08

fn main() {
    let progress = indicatif::MultiProgress::new();
    progress.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n").unwrap();
    progress.println("bbb\n").unwrap();
}
Ekleog commented 11 months ago

I had some fixes for this issue in https://github.com/console-rs/indicatif/pull/518 ; but they bitrotted before the end of code review; and I don't have any time to allocate it any longer.

Anyone looking at this, feel free to take over #518; as it's probably one rebase away from being able to fix this issue, and I introduced a test there which would easily be able to tell whether the fix actually works :)