//! This shows how an application can write on stderr
//! instead of stdout, thus making it possible to
//! the command API instead of the "old style" direct
//! unbuffered API.
//!
//! This particular example is only suited to Unix
//! for now.
//!
//! cargo run --example stderr

use std::io::{stderr, Write};

use crossterm::{
    cursor::{Hide, MoveTo, Show},
    event,
    event::{Event, KeyCode, KeyEvent},
    execute, queue,
    style::Print,
    terminal::{self, EnterAlternateScreen, LeaveAlternateScreen},
    Result,
};

const TEXT: &str = r#"
This screen is ran on stderr.
And when you hit enter, it prints on stdout.
This makes it possible to run an application and choose what will
be sent to any application calling yours.

For example, assuming you build this example with

    cargo build --bin stderr

and then you run it with

    cd "$(target/debug/stderr)"

what the application prints on stdout is used as argument to cd.

Try it out.

Hit any key to quit this screen:

1 will print `..`
2 will print `/`
3 will print `~`
Any other key will print this text (so that you may copy-paste)
"#;

fn run_app<W>(write: &mut W) -> Result<char>
where
    W: Write,
{
    queue!(
        write,
        EnterAlternateScreen, // enter alternate screen
        Hide                  // hide the cursor
    )?;

    let mut y = 1;
    for line in TEXT.split('\n') {
        queue!(write, MoveTo(1, y), Print(line.to_string()))?;
        y += 1;
    }

    write.flush()?;

    terminal::enable_raw_mode()?;
    let user_char = read_char()?; // we wait for the user to hit a key
    execute!(write, Show, LeaveAlternateScreen)?; // restore the cursor and leave the alternate screen

    terminal::disable_raw_mode()?;

    Ok(user_char)
}

pub fn read_char() -> Result<char> {
    loop {
        if let Event::Key(KeyEvent {
            code: KeyCode::Char(c),
            ..
        }) = event::read()?
        {
            return Ok(c);
        }
    }
}

// cargo run --example stderr
fn main() {
    match run_app(&mut stderr()).unwrap() {
        '1' => print!(".."),
        '2' => print!("/"),
        '3' => print!("~"),
        _ => println!("{}", TEXT),
    }
}
