Dropping of AlternateScreen does not flush stdout
When dropping alternate screen stdout
is not flushed, leading to messages on stderr
disappearing, or other processes using the same stdout
not having any output visible.
Here is a sample bin showing the issue:
extern crate termion;
use std::io;
use std::io::Write;
use termion::raw::IntoRawMode;
fn main() {
let raw = io::stdout().into_raw_mode().unwrap();
let screen = termion::screen::AlternateScreen::from(raw);
println!("This is stdout in alt screen.\r");
eprintln!("This is stderr in alt screen.\r");
::std::thread::sleep(::std::time::Duration::from_secs(1));
drop(screen);
// Comment this out to get both messages displayed:
// io::stdout().flush().ok();
eprintln!("This is stderr outside alt screen.\r");
println!("This is stdout outside alt screen.\r");
}
First two messages are shown for a second, then only the message on stdout is displayed after the screen is restored. If stdout is flushed before, then the alternate screen is really stopped before anything is written to stderr. As it is now, the two buffers are flushed independently.
This also causes problems with things like this pseudo code:
fn main() {
let command = select_command_in_alternate_screen()?;
fork_exec_wait(command);
println!("Done");
}
fn select_command_in_alternate_screen() -> Result<String, ()> {
let mut terminal = setup_alternate_screen();
// …
return Ok(command);
// implied drop(terminal) at the end of the function
}
The forked process (created using std::process::Command
, for example) inherits the same stdout and stderr FDs and starts writing to them before this process has flushed its buffers, so output on both stdout and stderr is lost as soon as the "Done"
message is finally flushed.
I think manually flushing at the drop
means that it would be a lot easier to use alternate screens in RAII-patterns that Rust is so good at. Right now I manually need to place flush
calls at each call site after a function using an alternate screen to be sure no message after it is lost.