Skip to content

Commit 0cf21a1

Browse files
joshkasayanarijit
authored andcommitted
feat: rewrite termion example
Fix up termion code by: - ensuring that errors when rendering / reading do not prevent restoring terminal - handle accept / cancel of the prompt - add a label (change logic to prompt for a name, and greet the person) - decompose into logical functions - add comments
1 parent 5638a62 commit 0cf21a1

File tree

1 file changed

+60
-31
lines changed

1 file changed

+60
-31
lines changed

examples/termion_input.rs

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,67 @@
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)?;
2644

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+
}
3053
}
3154
}
32-
33-
write!(stdout, "{}", Show)?;
3455
}
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);
3562

36-
println!("{}", input);
63+
write!(stdout, "{}{LABEL}", Goto(1, 1))?;
64+
backend::write(stdout, input.value(), input.cursor(), POSITION, 15)?;
65+
stdout.flush()?;
3766
Ok(())
3867
}

0 commit comments

Comments
 (0)