### Run Ratatui Example Source: https://github.com/sayanarijit/tui-input/blob/main/README.md Execute the ratatui example provided with the crate to see tui-input in action with the ratatui framework and crossterm backend. ```bash cargo run --example ratatui_crossterm_input ``` -------------------------------- ### Run Termion Example Source: https://github.com/sayanarijit/tui-input/blob/main/README.md Build and run the example for the termion backend. This requires enabling the 'termion' feature and disabling default features. ```bash cargo run --example termion_input --features termion --no-default-features ``` -------------------------------- ### Run Crossterm Example Source: https://github.com/sayanarijit/tui-input/blob/main/README.md Build and run the example specifically for the crossterm backend. Ensure to enable the 'crossterm' feature and disable default features. ```bash cargo run --example crossterm_input --features crossterm --no-default-features ``` -------------------------------- ### Full Ratatui Integration Example Source: https://context7.com/sayanarijit/tui-input/llms.txt A complete Ratatui TUI application demonstrating Normal and Editing modes, scrollable input, and message history. Requires `ratatui` and `tui-input` with the `crossterm` feature. ```rust use ratatui::{ crossterm::event::{self, Event, KeyCode}, layout::{Constraint, Layout}, style::{Color, Style}, widgets::{Block, List, Paragraph}, DefaultTerminal, Frame, }; use tui_input::backend::crossterm::EventHandler; use tui_input::Input; #[derive(Default)] struct App { input: Input, editing: bool, messages: Vec, } fn run(app: &mut App, terminal: &mut DefaultTerminal) -> std::io::Result<()> { loop { terminal.draw(|frame| render(app, frame))?; if let Event::Key(key) = event::read()? { if app.editing { match key.code { KeyCode::Enter => { app.messages.push(app.input.value_and_reset()); } KeyCode::Esc => { app.editing = false; } _ => { app.input.handle_event(&Event::Key(key)); } } } else { match key.code { KeyCode::Char('e') => { app.editing = true; } KeyCode::Char('q') => return Ok(()), _ => {} } } } } } fn render(app: &App, frame: &mut Frame) { let [input_area, messages_area] = Layout::vertical([ Constraint::Length(3), Constraint::Min(1), ]).areas(frame.area()); // Compute scroll so the cursor stays visible let width = input_area.width.max(3) - 3; let scroll = app.input.visual_scroll(width as usize); let style = if app.editing { Color::Yellow.into() } else { Style::default() }; let paragraph = Paragraph::new(app.input.value()) .style(style) .scroll((0, scroll as u16)) .block(Block::bordered().title("Input")); frame.render_widget(paragraph, input_area); // Position the terminal cursor over the active input character if app.editing { let x = app.input.visual_cursor().max(scroll) - scroll + 1; frame.set_cursor_position((input_area.x + x as u16, input_area.y + 1)); } let items: Vec = app.messages.iter().enumerate() .map(|(i, m)| format!( "{i}: {m}")) .collect(); frame.render_widget( List::new(items).block(Block::bordered().title("Messages")), messages_area, ); } fn main() -> std::io::Result<()> { let mut terminal = ratatui::init(); let result = run(&mut App::default(), &mut terminal); ratatui::restore(); result } ``` -------------------------------- ### Install tui-input with Different Backends Source: https://context7.com/sayanarijit/tui-input/llms.txt Add tui-input to your Cargo.toml, specifying the desired backend features. The default includes ratatui and crossterm. ```toml # ratatui + crossterm (default) tui-input = "0.15.3" ``` ```toml # ratatui + termion tui-input = { version = "0.15.3", features = ["ratatui-termion"], default-features = false } ``` ```toml # Raw crossterm (no ratatui) tui-input = { version = "0.15.3", features = ["crossterm"], default-features = false } ``` ```toml # Raw termion (no ratatui) tui-input = { version = "0.15.3", features = ["termion"], default-features = false } ``` ```toml # With serde support (any backend) tui-input = { version = "0.15.3", features = ["serde"] } ``` -------------------------------- ### Input::visual_cursor() and Input::visual_scroll() — Display-Column Rendering Source: https://context7.com/sayanarijit/tui-input/llms.txt Details `visual_cursor()` for getting the cursor's display column position (handling wide characters) and `visual_scroll()` for calculating the necessary scroll offset to fit text within a given widget width. ```APIDOC ## `Input::visual_cursor()` and `Input::visual_scroll()` — Display-Column Rendering `visual_cursor()` returns the cursor position in terminal display columns (accounting for wide characters). `visual_scroll()` computes the scroll offset needed to fit the value into a widget of a given column width. ```rust use tui_input::Input; // Full-width (double-column) CJK characters let input: Input = "(Hello, World!".into(); assert_eq!(input.cursor(), 13); // 13 codepoints assert_eq!(input.visual_cursor(), 23); // 23 display columns assert_eq!(input.visual_scroll(6), 18); // scroll offset for a 6-column widget // Used when rendering a ratatui Paragraph: // let scroll = input.visual_scroll(widget_width); // Paragraph::new(input.value()).scroll((0, scroll as u16)) ``` ``` -------------------------------- ### Input Struct Initialization and Value Management Source: https://context7.com/sayanarijit/tui-input/llms.txt Demonstrates how to create and manipulate the `Input` buffer, including setting initial values, modifying the cursor position, and converting the buffer back to a String. ```APIDOC ## Input Struct Initialization and Value Management `Input` holds the text value and cursor. It can be constructed from a string literal, a `String`, or via `Input::new()`. The cursor defaults to the end of the initial value. ```rust use tui_input::Input; // Create from a string literal let input: Input = "Hello World".into(); assert_eq!(input.value(), "Hello World"); assert_eq!(input.cursor(), 11); // cursor at end (codepoints) // Create with an explicit cursor position let input = Input::new("Hello World".to_string()).with_cursor(5); assert_eq!(input.cursor(), 5); // Replace the value programmatically (cursor moves to end) let input = Input::default().with_value("new value".to_string()); assert_eq!(input.value(), "new value"); // Convert back to String let s: String = input.into(); assert_eq!(s, "new value"); ``` ``` -------------------------------- ### Input::reset() and Input::value_and_reset() Source: https://context7.com/sayanarijit/tui-input/llms.txt Explains how to reset the input buffer and cursor to their default states using `reset()` and `value_and_reset()`, with `value_and_reset()` also returning the current buffer content. ```APIDOC ## `Input::reset()` and `Input::value_and_reset()` Reset the buffer and cursor back to defaults, optionally returning the current value. ```rust use tui_input::Input; let mut input: Input = "some text".into(); // Take the value and clear the buffer (typical "submit" pattern) let submitted = input.value_and_reset(); assert_eq!(submitted, "some text"); assert_eq!(input.value(), ""); assert_eq!(input.cursor(), 0); // Or reset without taking the value input.handle(tui_input::InputRequest::InsertChar('x')); input.reset(); assert_eq!(input.value(), ""); ``` ``` -------------------------------- ### Input::handle() - Dispatch Input Requests Source: https://context7.com/sayanarijit/tui-input/llms.txt Explains how to use the `handle` method of the `Input` struct to process various input requests, such as inserting characters, moving the cursor, and deleting characters. It also details the `StateChanged` response indicating modifications. ```APIDOC ## Input::handle() - Dispatch Input Requests `handle()` accepts an `InputRequest` and returns `Option`. `None` means the request was a no-op. `StateChanged { value, cursor }` reports whether the string content and/or cursor position changed. ```rust use tui_input::{Input, InputRequest, StateChanged}; let mut input: Input = "Hello Worl".into(); // Insert a character at the current cursor position let resp = input.handle(InputRequest::InsertChar('d')); assert_eq!(resp, Some(StateChanged { value: true, cursor: true })); assert_eq!(input.value(), "Hello World"); assert_eq!(input.cursor(), 11); // Move cursor left by one grapheme let resp = input.handle(InputRequest::GoToPrevChar); assert_eq!(resp, Some(StateChanged { value: false, cursor: true })); assert_eq!(input.cursor(), 10); // Delete the character before the cursor let resp = input.handle(InputRequest::DeletePrevChar); assert_eq!(resp, Some(StateChanged { value: true, cursor: true })); assert_eq!(input.value(), "Hello Worl"); // No-op: already at start input.handle(InputRequest::GoToStart); let resp = input.handle(InputRequest::GoToStart); assert_eq!(resp, None); ``` ``` -------------------------------- ### InputRequest — All Editing Actions Source: https://context7.com/sayanarijit/tui-input/llms.txt Demonstrates the usage of `InputRequest` for a comprehensive set of editing commands on an `Input` instance, including cursor movement, deletion of characters, words, and lines, and direct text insertion. ```APIDOC ## `InputRequest` — All Editing Actions `InputRequest` is the full set of editing commands. It is `Copy`, `Clone`, `PartialEq`, `Hash`, and optionally `serde`-serializable. ```rust use tui_input::{Input, InputRequest}; let mut input: Input = "first second, third.".into(); // --- Cursor movement --- input.handle(InputRequest::SetCursor(6)); // jump to codepoint 6 input.handle(InputRequest::GoToPrevChar); // ← one grapheme input.handle(InputRequest::GoToNextChar); // → one grapheme input.handle(InputRequest::GoToPrevWord); // ← to previous word boundary input.handle(InputRequest::GoToNextWord); // → to next word boundary input.handle(InputRequest::GoToStart); // jump to position 0 input.handle(InputRequest::GoToEnd); // jump to end // --- Deletion --- input.handle(InputRequest::DeletePrevChar); // backspace input.handle(InputRequest::DeleteNextChar); // delete input.handle(InputRequest::DeletePrevWord); // Ctrl+W — kill word backwards (added to yank) input.handle(InputRequest::DeleteNextWord); // Ctrl+Delete — kill word forwards (added to yank) input.handle(InputRequest::DeleteLine); // Ctrl+U — kill whole line (added to yank) input.handle(InputRequest::DeleteTillEnd); // Ctrl+K — kill to end of line (added to yank) // --- Yank / paste --- input.handle(InputRequest::Yank); // Ctrl+Y — paste from kill ring // --- Direct insert --- input.handle(InputRequest::InsertChar('!')); assert_eq!(input.value(), "first second, third.!"); ``` ``` -------------------------------- ### Resetting tui-input Input Buffer Source: https://context7.com/sayanarijit/tui-input/llms.txt Shows how to reset the input buffer and cursor to their default states using `reset()` or `value_and_reset()`. `value_and_reset()` is useful for typical submit patterns. ```rust use tui_input::Input; let mut input: Input = "some text".into(); // Take the value and clear the buffer (typical "submit" pattern) let submitted = input.value_and_reset(); assert_eq!(submitted, "some text"); assert_eq!(input.value(), ""); assert_eq!(input.cursor(), 0); // Or reset without taking the value input.handle(tui_input::InputRequest::InsertChar('x')); input.reset(); assert_eq!(input.value(), ""); ``` -------------------------------- ### tui-input Display-Column Rendering Source: https://context7.com/sayanarijit/tui-input/llms.txt Illustrates how to use `visual_cursor()` and `visual_scroll()` to handle wide characters and calculate display column positions for rendering in a widget. ```rust use tui_input::Input; // Full-width (double-column) CJK characters let input: Input = "(Hello, World!".into(); assert_eq!(input.cursor(), 13); // 13 codepoints assert_eq!(input.visual_cursor(), 23); // 23 display columns assert_eq!(input.visual_scroll(6), 18); // scroll offset for a 6-column widget // Used when rendering a ratatui Paragraph: // let scroll = input.visual_scroll(widget_width); // Paragraph::new(input.value()).scroll((0, scroll as u16)) ``` -------------------------------- ### Serde Support for Input Structs Source: https://context7.com/sayanarijit/tui-input/llms.txt Demonstrates serialization and deserialization of `Input` and `InputRequest` structs using Serde when the `serde` feature is enabled. The `Input` struct serializes to its string value. ```rust // Cargo.toml: tui-input = { version = "0.15.3", features = ["serde"] } use tui_input::{Input, InputRequest}; let input = Input::new("hello world".to_string()).with_cursor(5); // Serialize let json = serde_json::to_string(&input).unwrap(); // {"value":"hello world","cursor":5,"yank":"","last_was_cut":false} // Deserialize let restored: Input = serde_json::from_str(&json).unwrap(); assert_eq!(restored.value(), "hello world"); assert_eq!(restored.cursor(), 5); // InputRequest is also serializable (useful for event logging / replay) let req = InputRequest::InsertChar('!'); let json = serde_json::to_string(&req).unwrap(); // {"InsertChar":"!"} let req2: InputRequest = serde_json::from_str(&json).unwrap(); assert_eq!(req, req2); ``` -------------------------------- ### Low-Level Crossterm Rendering with `write()` Source: https://context7.com/sayanarijit/tui-input/llms.txt The `write` function offers a low-level mechanism for rendering the input field to the terminal. It precisely controls the output by positioning the cursor, highlighting the character at the cursor with reverse-video, and handling text overflow within a specified display width, ensuring the input is displayed correctly. ```APIDOC ## `backend::crossterm::write()` — Low-Level Crossterm Renderer Renders the input field at a specific terminal position with a fixed display width. Characters before the cursor are printed normally; the character at the cursor is highlighted with reverse-video; characters after are printed normally. Scrolls automatically when the value is wider than `width`. ```rust use std::io::{stdout, Write}; use crossterm::{cursor::MoveTo, execute, queue, style::Print, terminal::{enable_raw_mode, disable_raw_mode}}; use tui_input::backend::crossterm as backend; use tui_input::Input; let mut stdout = stdout(); let input = Input::from("Hello, terminal!"); // Render the field at column 10, row 2, with a display width of 20 columns backend::write( &mut stdout, input.value(), input.cursor(), (10, 2), // (x, y) position 20, // display width in columns )?; stdout.flush()?; // Output: moves cursor to (10,2), prints value with reverse-video cursor highlight ``` ``` -------------------------------- ### Low-Level Crossterm Renderer with write() Source: https://context7.com/sayanarijit/tui-input/llms.txt Renders the input field at a specified terminal position and display width. It highlights the cursor with reverse-video and automatically scrolls if the input value exceeds the display width. Requires enabling raw mode. ```rust use std::io::{stdout, Write}; use crossterm::{cursor::MoveTo, execute, queue, style::Print, terminal::{enable_raw_mode, disable_raw_mode}}; use tui_input::backend::crossterm as backend; use tui_input::Input; let mut stdout = stdout(); let input = Input::from("Hello, terminal!"); // Render the field at column 10, row 2, with a display width of 20 columns backend::write( &mut stdout, input.value(), input.cursor(), (10, 2), // (x, y) position 20, // display width in columns )?; stdout.flush()?; // Output: moves cursor to (10,2), prints value with reverse-video cursor highlight ``` -------------------------------- ### Initialize and Manipulate tui-input::Input Buffer Source: https://context7.com/sayanarijit/tui-input/llms.txt Create an Input buffer from string literals or Strings, set an explicit cursor position, replace the value, or convert it back to a String. The cursor defaults to the end of the initial value. ```rust use tui_input::Input; // Create from a string literal let input: Input = "Hello World".into(); assert_eq!(input.value(), "Hello World"); assert_eq!(input.cursor(), 11); // cursor at end (codepoints) // Create with an explicit cursor position let input = Input::new("Hello World".to_string()).with_cursor(5); assert_eq!(input.cursor(), 5); // Replace the value programmatically (cursor moves to end) let input = Input::default().with_value("new value".to_string()); assert_eq!(input.value(), "new value"); // Convert back to String let s: String = input.into(); assert_eq!(s, "new value"); ``` -------------------------------- ### Unicode and Grapheme Cluster Support in tui-input Source: https://context7.com/sayanarijit/tui-input/llms.txt Demonstrates how tui-input correctly handles complex Unicode characters, including composed accents, emoji with modifiers, ZWJ sequences, and flag emojis, by treating them as single grapheme clusters for navigation and deletion. ```rust use tui_input::{Input, InputRequest}; // Combining accent: "á" = "a" + U+0301 = 1 grapheme, 2 codepoints let mut input: Input = "xa\u{0301}y".into(); // cursor at codepoint 4 input.handle(InputRequest::GoToPrevChar); assert_eq!(input.cursor(), 1); // skipped both codepoints as one grapheme // Complex emoji: 🤦🏼‍♂️ = 1 grapheme, 5 codepoints let mut input: Input = "x🤦🏼\u{200D}♂\u{FE0F}y".into(); // cursor at codepoint 7 input.handle(InputRequest::GoToPrevChar); assert_eq!(input.cursor(), 1); // entire emoji treated as one grapheme // Flag emoji: 🇧🇸 = 1 grapheme, 2 codepoints let mut input: Input = "x🇧🇸y".into(); // cursor at codepoint 4 input.handle(InputRequest::GoToPrevChar); assert_eq!(input.cursor(), 1); // flag treated as one grapheme ``` -------------------------------- ### Add tui-input to Cargo.toml Source: https://github.com/sayanarijit/tui-input/blob/main/README.md Specify the tui-input dependency in your Cargo.toml file. Choose the appropriate feature for your backend (ratatui::crossterm, crossterm, or termion). ```toml tui-input = "*" ``` ```toml # Direct crossterm tui-input = { version = "*", features = ["crossterm"], default-features = false } ``` ```toml # termion tui-input = { version = "*", features = ["termion"], default-features = false } ``` -------------------------------- ### Termion Backend Event Handling Source: https://context7.com/sayanarijit/tui-input/llms.txt Handles keyboard events using the Termion backend for TUI input. Note that word-movement key bindings are not available with Termion. ```rust use std::io::{stdin, stdout, Write}; use termion::{event::{Event, Key}, input::TermRead, raw::IntoRawMode}; use tui_input::backend::termion::{self as backend, EventHandler}; use tui_input::Input; let mut stdout = stdout().into_raw_mode()?; let mut input: Input = "World".into(); for event in stdin().events() { match event? { Event::Key(Key::Char('\n')) => { println!("\r\nHello, {}!", input.value()); break; } Event::Key(Key::Esc) => break, event => { if input.handle_event(&event).is_some() { // re-render backend::write(&mut stdout, input.value(), input.cursor(), (6, 0), 15)?; stdout.flush()?; } } } } ``` -------------------------------- ### Handle Input Requests with tui-input::Input::handle() Source: https://context7.com/sayanarijit/tui-input/llms.txt Dispatch InputRequests to the Input buffer using the handle() method. It returns Option indicating if the value or cursor position changed. No-ops return None. ```rust use tui_input::{Input, InputRequest, StateChanged}; let mut input: Input = "Hello Worl".into(); // Insert a character at the current cursor position let resp = input.handle(InputRequest::InsertChar('d')); assert_eq!(resp, Some(StateChanged { value: true, cursor: true })); assert_eq!(input.value(), "Hello World"); assert_eq!(input.cursor(), 11); // Move cursor left by one grapheme let resp = input.handle(InputRequest::GoToPrevChar); assert_eq!(resp, Some(StateChanged { value: false, cursor: true })); assert_eq!(input.cursor(), 10); // Delete the character before the cursor let resp = input.handle(InputRequest::DeletePrevChar); assert_eq!(resp, Some(StateChanged { value: true, cursor: true })); assert_eq!(input.value(), "Hello Worl"); // No-op: already at start input.handle(InputRequest::GoToStart); let resp = input.handle(InputRequest::GoToStart); assert_eq!(resp, None); ``` -------------------------------- ### tui-input InputRequest Editing Actions Source: https://context7.com/sayanarijit/tui-input/llms.txt Demonstrates various editing actions using InputRequest, including cursor movement, deletion, and direct character insertion. Ensure the Input struct is initialized before use. ```rust use tui_input::{Input, InputRequest}; let mut input: Input = "first second, third.".into(); // --- Cursor movement --- input.handle(InputRequest::SetCursor(6)); // jump to codepoint 6 input.handle(InputRequest::GoToPrevChar); // ← one grapheme input.handle(InputRequest::GoToNextChar); // → one grapheme input.handle(InputRequest::GoToPrevWord); // ← to previous word boundary input.handle(InputRequest::GoToNextWord); // → to next word boundary input.handle(InputRequest::GoToStart); // jump to position 0 input.handle(InputRequest::GoToEnd); // jump to end // --- Deletion --- input.handle(InputRequest::DeletePrevChar); // backspace input.handle(InputRequest::DeleteNextChar); // delete input.handle(InputRequest::DeletePrevWord); // Ctrl+W — kill word backwards (added to yank) input.handle(InputRequest::DeleteNextWord); // Ctrl+Delete — kill word forwards (added to yank) input.handle(InputRequest::DeleteLine); // Ctrl+U — kill whole line (added to yank) input.handle(InputRequest::DeleteTillEnd); // Ctrl+K — kill to end of line (added to yank) // --- Yank / paste --- input.handle(InputRequest::Yank); // Ctrl+Y — paste from kill ring // --- Direct insert --- input.handle(InputRequest::InsertChar('!')); assert_eq!(input.value(), "first second, third.!"); ``` -------------------------------- ### Yank / Kill Ring Source: https://context7.com/sayanarijit/tui-input/llms.txt Explains the behavior of the yank/kill ring, where consecutive deletion operations accumulate text that can be pasted using `InputRequest::Yank`. Other actions reset this accumulation. ```APIDOC ## Yank / Kill Ring Consecutive `DeletePrevWord`, `DeleteNextWord`, `DeleteLine`, and `DeleteTillEnd` requests accumulate text in the yank buffer. Any other request (including `InsertChar` or `DeletePrevChar`) resets the accumulation. `Yank` inserts the yank buffer at the cursor. ```rust use tui_input::{Input, InputRequest}; let mut input: Input = "first second, third.".into(); // Consecutive DeletePrevWord calls accumulate into yank input.handle(InputRequest::DeletePrevWord); // yanks "third." assert_eq!(input.value(), "first second, "); input.handle(InputRequest::DeletePrevWord); // yanks "second, " prepended → "second, third." assert_eq!(input.value(), "first "); // Paste the accumulated yank at cursor input.handle(InputRequest::Yank); assert_eq!(input.value(), "first second, third."); // Breaking the sequence with another action resets accumulation let mut input: Input = "first second, third.".into(); input.handle(InputRequest::DeletePrevWord); // yanks "third." input.handle(InputRequest::InsertChar('x')); // breaks cut sequence input.handle(InputRequest::DeletePrevChar); input.handle(InputRequest::DeletePrevWord); // new yank: "second, " only // yank buffer is now just "second, " — not accumulated with "third." ``` ``` -------------------------------- ### Mapping Crossterm Events to Input Requests Source: https://context7.com/sayanarijit/tui-input/llms.txt The `to_input_request` function translates crossterm `Event` types into `InputRequest` enums, allowing for seamless integration with the tui-input library. It handles various key presses, including character insertions, deletions, and cursor movements, while intentionally ignoring unmapped events like `Tab`. ```APIDOC ## `backend::crossterm::to_input_request()` — Map Crossterm Events Converts a `crossterm::event::Event` into an `Option`. Returns `None` for events with no input mapping (e.g., `Tab`, non-key events). ```rust use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers}; use tui_input::backend::crossterm::to_input_request; use tui_input::InputRequest; // Regular character let evt = Event::Key(KeyEvent { code: KeyCode::Char('a'), modifiers: KeyModifiers::NONE, kind: KeyEventKind::Press, state: KeyEventState::NONE, }); assert_eq!(to_input_request(&evt), Some(InputRequest::InsertChar('a'))); // Key repeat also maps let evt = Event::Key(KeyEvent { kind: KeyEventKind::Repeat, ..evt.as_key_event().unwrap().clone() }); // (same result as Press) // Ctrl+U → DeleteLine let evt = Event::Key(KeyEvent { code: KeyCode::Char('u'), modifiers: KeyModifiers::CONTROL, kind: KeyEventKind::Press, state: KeyEventState::NONE, }); assert_eq!(to_input_request(&evt), Some(InputRequest::DeleteLine)); // Tab → None (intentionally unmapped) let tab = Event::Key(KeyEvent { code: KeyCode::Tab, modifiers: KeyModifiers::NONE, kind: KeyEventKind::Press, state: KeyEventState::NONE, }); assert_eq!(to_input_input_request(&tab), None); ``` **Full crossterm key binding table:** | Key Combination | `InputRequest` | |---|---| | `Backspace`, `Ctrl+H` | `DeletePrevChar` | | `Delete` | `DeleteNextChar` | | `←`, `Ctrl+B` | `GoToPrevChar` | | `Ctrl+←`, `Meta+B` | `GoToPrevWord` | | `→`, `Ctrl+F` | `GoToNextChar` | | `Ctrl+→`, `Meta+F` | `GoToNextWord` | | `Ctrl+U` | `DeleteLine` | | `Ctrl+W`, `Meta+D`, `Alt+Backspace` | `DeletePrevWord` | | `Ctrl+Delete` | `DeleteNextWord` | | `Ctrl+K` | `DeleteTillEnd` | | `Ctrl+Y` | `Yank` | | `Ctrl+A`, `Home` | `GoToStart` | | `Ctrl+E`, `End` | `GoToEnd` | | `Char(c)` (no/shift/Ctrl+Alt mods) | `InsertChar(c)` | ``` -------------------------------- ### tui-input Yank/Kill Ring Behavior Source: https://context7.com/sayanarijit/tui-input/llms.txt Explains the yank/kill ring mechanism where consecutive deletion actions accumulate text, which can then be pasted using `Yank`. Other actions reset the accumulation. ```rust use tui_input::{Input, InputRequest}; let mut input: Input = "first second, third.".into(); // Consecutive DeletePrevWord calls accumulate into yank input.handle(InputRequest::DeletePrevWord); // yanks "third." assert_eq!(input.value(), "first second, "); input.handle(InputRequest::DeletePrevWord); // yanks "second, " prepended → "second, third." assert_eq!(input.value(), "first "); // Paste the accumulated yank at cursor input.handle(InputRequest::Yank); assert_eq!(input.value(), "first second, third."); // Breaking the sequence with another action resets accumulation let mut input: Input = "first second, third.".into(); input.handle(InputRequest::DeletePrevWord); // yanks "third." input.handle(InputRequest::InsertChar('x')); // breaks cut sequence input.handle(InputRequest::DeletePrevChar); input.handle(InputRequest::DeletePrevWord); // new yank: "second, " only // yank buffer is now just "second, " — not accumulated with "third." ``` -------------------------------- ### Ergonomic Event Dispatch with EventHandler Trait Source: https://context7.com/sayanarijit/tui-input/llms.txt Import the EventHandler trait to use the handle_event method, which combines event translation and state mutation for tui-input. This allows for a streamlined way to process input events. ```rust use crossterm::event::{read, Event, KeyCode}; use tui_input::backend::crossterm::EventHandler; use tui_input::Input; let mut input = Input::from("World"); loop { let event = read()?; match event { Event::Key(key) => match key.code { KeyCode::Enter => { let value = input.value_and_reset(); println!("Submitted: {value}"); break; } KeyCode::Esc => break, _ => { // Returns Some(StateChanged) if the input was modified if input.handle_event(&event).is_some() { // re-render only when state changed } } }, _ => {} } } ``` -------------------------------- ### Map Crossterm Events to InputRequest with to_input_request Source: https://context7.com/sayanarijit/tui-input/llms.txt Converts crossterm::event::Event into tui_input::InputRequest. Returns None for events without a direct input mapping, such as Tab or non-key events. Handles regular character insertion and key repeats. ```rust use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers}; use tui_input::backend::crossterm::to_input_request; use tui_input::InputRequest; // Regular character let evt = Event::Key(KeyEvent { code: KeyCode::Char('a'), modifiers: KeyModifiers::NONE, kind: KeyEventKind::Press, state: KeyEventState::NONE, }); assert_eq!(to_input_request(&evt), Some(InputRequest::InsertChar('a'))); // Key repeat also maps let evt = Event::Key(KeyEvent { kind: KeyEventKind::Repeat, ..evt.as_key_event().unwrap().clone() }); // (same result as Press) // Ctrl+U → DeleteLine let evt = Event::Key(KeyEvent { code: KeyCode::Char('u'), modifiers: KeyModifiers::CONTROL, kind: KeyEventKind::Press, state: KeyEventState::NONE, }); assert_eq!(to_input_request(&evt), Some(InputRequest::DeleteLine)); // Tab → None (intentionally unmapped) let tab = Event::Key(KeyEvent { code: KeyCode::Tab, modifiers: KeyModifiers::NONE, kind: KeyEventKind::Press, state: KeyEventState::NONE, }); assert_eq!(to_input_request(&tab), None); ``` -------------------------------- ### Ergonomic Event Handling with `EventHandler` Trait Source: https://context7.com/sayanarijit/tui-input/llms.txt The `EventHandler` trait provides a convenient way to process terminal events directly within your input handling logic. By implementing this trait, you can call `input.handle_event(&event)` to translate and apply crossterm events to the input state in a single step, simplifying your event loop. ```APIDOC ## `backend::crossterm::EventHandler` Trait — Ergonomic Event Dispatch Import this trait to call `input.handle_event(&event)` directly, combining event translation and state mutation in one step. ```rust use crossterm::event::{read, Event, KeyCode}; use tui_input::backend::crossterm::EventHandler; use tui_input::Input; let mut input = Input::from("World"); loop { let event = read()?; match event { Event::Key(key) => match key.code { KeyCode::Enter => { let value = input.value_and_reset(); println!("Submitted: {value}"); break; } KeyCode::Esc => break, _ => { // Returns Some(StateChanged) if the input was modified if input.handle_event(&event).is_some() { // re-render only when state changed } } }, _ => {} } } ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.