|
1 |
| -use std::io::{stdin, stdout, Result, Write}; |
2 |
| -use termion::cursor::{Hide, Show}; |
3 |
| -use termion::event::{Event, Key}; |
4 |
| -use termion::input::TermRead; |
5 |
| -use termion::raw::IntoRawMode; |
6 |
| -use termion::screen::IntoAlternateScreen; |
7 |
| -use tui_input::backend::termion as backend; |
8 |
| -use tui_input::backend::termion::EventHandler; |
9 |
| -use tui_input::Input; |
10 |
| - |
11 |
| -fn main() -> Result<()> { |
12 |
| - let mut input: Input = "Hello ".into(); |
13 |
| - { |
14 |
| - let stdin = stdin(); |
15 |
| - let mut stdout = stdout().into_raw_mode()?.into_alternate_screen()?; |
16 |
| - |
17 |
| - write!(&mut stdout, "{}", Hide)?; |
18 |
| - backend::write(&mut stdout, input.value(), input.cursor(), (0, 0), 15)?; |
19 |
| - stdout.flush()?; |
20 |
| - |
21 |
| - for evt in stdin.events() { |
22 |
| - let evt = evt?; |
23 |
| - if evt == Event::Key(Key::Esc) || evt == Event::Key(Key::Char('\n')) { |
24 |
| - break; |
25 |
| - } |
| 1 | +//! This example demonstrates how to use the `tui_input` crate with the `crossterm` backend. |
| 2 | +//! The example prompts the user for their name and prints a greeting. |
| 3 | +//! The user can cancel the input by pressing `Esc` or accept the input by pressing `Enter`. |
| 4 | +
|
| 5 | +use std::io::{self, stdin, stdout, Write}; |
| 6 | + |
| 7 | +use termion::{ |
| 8 | + cursor::{Goto, Hide, Show}, |
| 9 | + event::{Event, Key}, |
| 10 | + input::TermRead, |
| 11 | + raw::IntoRawMode, |
| 12 | + screen::IntoAlternateScreen, |
| 13 | +}; |
| 14 | +use tui_input::{ |
| 15 | + backend::termion::{self as backend, EventHandler}, |
| 16 | + Input, |
| 17 | +}; |
| 18 | + |
| 19 | +fn main() -> io::Result<()> { |
| 20 | + let mut stdout = stdout().into_raw_mode()?.into_alternate_screen()?; |
| 21 | + write!(stdout, "{}", Hide)?; |
| 22 | + let name = get_user_name(&mut stdout); |
| 23 | + write!(stdout, "{}", Show)?; |
| 24 | + drop(stdout); // disable raw mode and leave alternate screen |
| 25 | + |
| 26 | + match name? { |
| 27 | + Some(name) => println!("Hello {name}!"), |
| 28 | + None => println!("Goodbye!"), |
| 29 | + } |
| 30 | + Ok(()) |
| 31 | +} |
| 32 | + |
| 33 | +/// Prompts the user for their name. |
| 34 | +/// |
| 35 | +/// Returns `None` if the user cancels the input otherwise returns the user's name. If the user |
| 36 | +/// presses `Esc` the input is cancelled. If the user presses `Enter` the input is accepted. |
| 37 | +/// |
| 38 | +/// # Errors |
| 39 | +/// |
| 40 | +/// Returns an error if reading or writing to the terminal fails. |
| 41 | +fn get_user_name(stdout: &mut impl Write) -> io::Result<Option<String>> { |
| 42 | + let mut input: Input = "World".into(); |
| 43 | + render_prompt(stdout, &input)?; |
26 | 44 |
|
27 |
| - if input.handle_event(&evt).is_some() { |
28 |
| - backend::write(&mut stdout, input.value(), input.cursor(), (0, 0), 15)?; |
29 |
| - stdout.flush()?; |
| 45 | + for event in stdin().events() { |
| 46 | + match event? { |
| 47 | + Event::Key(Key::Esc) => return Err(io::Error::other("error")), |
| 48 | + Event::Key(Key::Char('\n')) => return Ok(Some(input.to_string())), |
| 49 | + event => { |
| 50 | + if input.handle_event(&event).is_some() { |
| 51 | + render_prompt(stdout, &input)?; |
| 52 | + } |
30 | 53 | }
|
31 | 54 | }
|
32 |
| - |
33 |
| - write!(stdout, "{}", Show)?; |
34 | 55 | }
|
| 56 | + Ok(None) // reached end of input |
| 57 | +} |
| 58 | + |
| 59 | +fn render_prompt(stdout: &mut impl Write, input: &Input) -> io::Result<()> { |
| 60 | + const LABEL: &str = "Name: "; |
| 61 | + const POSITION: (u16, u16) = (LABEL.len() as u16, 0); |
35 | 62 |
|
36 |
| - println!("{}", input); |
| 63 | + write!(stdout, "{}{LABEL}", Goto(1, 1))?; |
| 64 | + backend::write(stdout, input.value(), input.cursor(), POSITION, 15)?; |
| 65 | + stdout.flush()?; |
37 | 66 | Ok(())
|
38 | 67 | }
|
0 commit comments