terminal icon indicating copy to clipboard operation
terminal copied to clipboard

Printing continues at wrong position when the terminal instance gets out of scope

Open phil0x2e opened this issue 6 years ago • 8 comments

Take this Code (I'm using crossterm-backend):

use terminal::{Action, Clear, error, Retrieved, Value};
use std::io::Write;
pub fn main() -> error::Result<()> {
    {
        let mut terminal = terminal::stdout();
        // perform an single action.
        terminal.act(Action::ClearTerminal(Clear::All))?;
        // batch multiple actions.
        for i in 0..10 {
            terminal.batch(Action::MoveCursorTo(0, i))?;
            terminal.write(format!("{}", i).as_bytes());
        }
        // execute batch.
        terminal.flush_batch();

        println!("\ntest1");
    }
    println!("test2");
    Ok(())
}

The output for me looks something like this:

test2
[user@host]$ 
2
3
4
5
6
7
8
9
test1

Is there a way to prevent this behaviour? If not terminal seems to be not suited for use in a library, because anyone that's using the library would always need to keep an instance of the Terminal struct alive (Or at least a struct from the library using it, that itself keeps an instance of Terminal) to be able to properly print something afterwards.

EDIT: Even when you just create an instance of Terminal and do nothing with it and end its scope, this problem occurs.

phil0x2e avatar Feb 25 '20 20:02 phil0x2e

That is weird, I have no clue why that happens. Over here

https://github.com/crossterm-rs/terminal/blob/master/src/backend/crossterm/implementation.rs#L121

I have the drop function. Here it disables raw modes and goes back to the default screen. Since you haven't enabled raw modes and switched to alternate screen this 'shouldn't' do anything. However, maybe it triggers some terminal behavior. This can be tested by simply debugging and commenting on the functions in the drop method.

TimonPost avatar Feb 26 '20 06:02 TimonPost

The issue seems to be the io::stdout().execute(terminal::LeaveAlternateScreen) function call. When I comment out that line in the drop function I get the expected result:

0
1
2
3
4
5
6
7
8
9
test1
test2
[user@host]$ 

phil0x2e avatar Feb 26 '20 13:02 phil0x2e

Are you able to reproduce the wrong behaviour? For me it happens in almost any terminal I tried, like urxvt, gnome-terminal or xterm. The only terminals, where it works correctly is the virtual terminal of my os and the integrated terminal I use inside of the atom editor.

phil0x2e avatar Feb 26 '20 14:02 phil0x2e

I can give it a shot in some hours

TimonPost avatar Feb 26 '20 14:02 TimonPost

@TimonPost Is there an update on this? I want to be able to write to stdout without the screen clearing whenever the terminal instance goes out of scope. For example, when the program ends I want to be able to see the command history.

bhgomes avatar Sep 06 '20 17:09 bhgomes

@phil0x2e @TimonPost I found that if one runs terminal.act(Action::EnterAlternateScreen) right before the terminal goes out of scope the problem goes away, presumably cancelling out the extra terminal.act(Action::LeaveAlternateScreen) in the drop. This is a less-than ideal solution, but it seems to work. I'm not sure what the best API choice is here.

bhgomes avatar Sep 15 '20 02:09 bhgomes

Hi there, correct, sorry I totally mist this issue. It's correct that raw modes, alternate screen, and mouse capture is disabled at the drop

https://github.com/crossterm-rs/terminal/blob/master/src/backend/crossterm/implementation.rs#L122

I chose this behavior because when a program stops we need to disable those things such that the terminal is back into its original modes. A solution could be, is by storing the terminal instance in an Box or something like that.

TimonPost avatar Sep 15 '20 06:09 TimonPost

@TimonPost Like @bhgomes mentioned it also happens after the program terminates, so you'll never be able to print something, that still needs to be read after your program ended. That really limits the use of this library to very interactive applications. Also that sadly makes it very cumbersome in a library, especially when it only provides functions to the user.

phil0x2e avatar Sep 16 '20 14:09 phil0x2e